I try to run batch file in java, but file performed not completely. Code look like:
Runtime.getRuntime().exec("cmd /c call "+path);
When I try to run it manually, without java, batch works correct.
Batch file contains next code:
cd C:\Downloads\
if not exist Documents mkdir Documents
move *.odt Documents
move *.doc Documents
if not exist Archives mkdir Archives
move *.tar Archives
move *.gz Archives
if not exist Music mkdir Music
move *.mp3 Music
Java complete batch only to fifth line. Has anyone faced this?
Hm, with batch, it stoped again here. And Java code: link. If add to somename.ogg to downloads folder, script goes to next line. All folders (Archives, Documents etc) are already exists, and downloads folder doesn't contain *.zip, *.tar, *.docx, *pdf files, but these lines passed without problems. Why it stoped precisely at ogg-line?
I think the problem is that there is a bug in your batch script. The MSDN documentation for the if command states this:
You cannot use the if command to test directly for a directory, but the null (NUL) device does exist in every directory. As a result, you can test for the null device to determine whether a directory exists. The following example tests for the existence of a directory:
if exist c:\mydir\nul goto process
Now the way you are using it (if not exist directory mkdir directory) is likely to succeed if the directory doesn't exist ... but attempt to create the directory a second time if it does exist. Ooops ...
Now, your Java application read and printed out the contents of the error stream for the process, you'd most likely see an error message telling you that the Archives directory already existed. Ignoring the output is asking for trouble, IMO.
I bet path in your Java program contains spaces or something similar. Are you quoting that properly?
Btw: Runtime.exec() has been superseeded with ProcessBuilder which can handle arguments much better than Runtime.exec()
Try this:
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "call \"" + path "\"");
builder.start();
OMG, GUYS!
I don't understand why, but:
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "call", "\"" + "sort.bat" + "\"");
builder.start();
doesn't works, BUT:
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "call", "\"" + "sort.bat" + "\"");
BufferedReader br = new BufferedReader(new InputStreamReader(builder.start().getInputStream()));
String line;
while ((line=br.readLine())!=null) {
System.out.println(line);
}
works correctly! %)
If anybody understands this, please, explain this.
If you're not careful with your stdout and stderr streams it's very easy to deadlock ProcessBuilder or Runtime.exec(). The article When Runtime.exec() won't over at JavaWorld contains a lot of useful information on this and a couple of other pitfalls.
If possible, I would suggest using Commons Exec because all the required stream pumping is done for you.
Related
I have written a shell script file which extracts the files, Please see below.
File Name: unzip.sh
#/bin/sh
cd /home/zip;
UNZIPDIR=/home/unzip/;
for i in *.zip; do
unzip "$i" -d "$UNZIPDIR"
rm "$i";
done;
This shell script executes sucessfuly on putty,
$> ./zip.sh
As i wanted to execute this script from my java class while i have tried several ways to invoke/execute the shell script file but it's not executing. Please see below java code.
//First try
File executorDirectory = new File("/home/zip");
ProcessBuilder processBuilder = new ProcessBuilder("./unzip.sh");
processBuilder.directory(executorDirectory);
Process p = processBuilder.start();
p.waitFor()
//Second try
Process p = Runtime.getRuntime().exec("/home/zip/unzip.sh");
The problem is that you fail to account for the process' standard output/error (as mentioned by #Yazan in the comments). You need to .get{Output,Error}Stream() from the created process and read from them (even if it is only to discard it).
The real problem however is that you use an external shell script for something which is entirely doable in Java itself. See this page which gives an example of how to extract a zip file entirely with Java code; to delete a file, use Files.delete().
From my application I have to execute an external jar of which I do not have the source.
Given an input file, it processes it, creates an "output" directory and puts in it an mxml output file. Problem is: it creates said directory in tomcat/bin instead of inside the directory of the original file.
Here's what I've tried so far.
Initially
Process p = new ProcessBuilder("java -jar "+newfile.getParent()+"\\converter.jar "+newfile.getPath()+" -mxml").start();
Then, seeing how from console the "output" directory was created in the directory the command was called from, I tried:
String startSim[] = {"cd "+newfile.getParent()+"\\" , "java -jar converter.jar "+newfile.getName()+" -mxml"};
try {
Runtime.getRuntime().exec(startSim).waitFor();
} catch (Exception e) {
e.printStackTrace();
System.out.println("Log non creato.");
}
But with this I get the "file not found" exception for the first instruction. Does anyone know how to possibly solve this problem? I'd like to avoid having to reach for my output file all the way in my tomcat/bin directory.
Thanks for any suggestion!
Paolo
P.s.: by the way, before trying all this I tried simply calling the method I need from the library, but had the same exact problem. So I resolved to execute the jar, instead. And here we are. :)
You can set working directory using ProcessBuilder.directory() method:
ProcessBuilder pb = new ProcessBuilder();
pb.directory(new File("mydirectory"));
pb.command(......);
etc
This does not work for you when you are using Runtime.exec() because cd command is a functionality of shell. You could solve it using this technique but you have to create platform specific command with prefix like cmd /c on windows or /bin/sh on Linux. This way is definitely not recommended.
But in your specific case you do not neither first nor second solution. Actually you are starting one java process from another. Why? you can easily invoke the main() method of the second process directly.
Take a look on META-INF/MANIFEST.mf file from converter.jar. Field Main-Class contains the fully qualified name of main class. Let's say it is com.converters.Main (just for example). In this case you can invoke
com.converters.Main.main(new String[] {newFile.getPath(), "-mxml"});
directly from your code. Just add the jar to your classpath.
Concerning to changing working directory in this case. Check again whether you really need this or your converters.jar supports parameter that does this.
A lazy approach to this may be going to the root directory and descending from there to your tomcat bin directory .
I want to run some unix/shell commands in Java and process the output. I used getRuntime.exec(), but it is not giving correct output for some commands like ls directory_path/*.tar.gz . For that command my program is not giving any output but it is giving error saying No such file or directory. But the same command is giving correct output on command prompt.
Is there any other way to execute commands which include wildcards in Java?
Is there any other way to execute commands which include wildcards in Java?
Yes there is.
You have three potential problems in your code:
Assuming you want to see the output of the external command you need to take care of the output it produces, and print it yourself.
Follow the example I've provided over here:
How to make a java program to print both out.println() and err.println() statements?
The shell expansion of * doesn't work if you naively go through Runtime.exec.You have to go through /bin/bash explicitly.
If you try to list the content of directory_path/*.tar.gz you should know that (if you're not starting with a /) directory_path will be resolved relative to the current working directory. Try at first to give the absolute path to make sure it works, and then try to figure out why it can't find the relative path.
Here's a complete example that should work:
Process proc = new ProcessBuilder("/bin/bash", "-c",
"ls /.../directory_path/*.tar.gz").start();
Reader reader = new InputStreamReader(proc.getInputStream());
int ch;
while ((ch = reader.read()) != -1)
System.out.print((char) ch);
reader.close();
That is because you specified a relative path to the directory and your application is running in a working directory. The path you specified is relative to that working directory.
To find out what the absolute path is, you can check out the working directory.
System.out.println("Working directory: " + System.getProperty("user.dir"));
"ls directory_path/*.tar.gz" works relative to CURRENT directory.
I have a script, which is test.sh on Ubuntu. I want to run it from Java. I know I have to use Runtime.getRuntime().exec();
Don't I have to fill the exec parenthesis with the location of test.sh? I am typing /home/main/ss/test.sh
I do not get any error messages but when I searched the folder, I saw that script did not work. How can I fix it?
You should really look at Process Builder. It is really built for this kind of thing.
ProcessBuilder pb = new ProcessBuilder("myshellScript.sh", "myArg1", "myArg2");
Map<String, String> env = pb.environment();
env.put("VAR1", "myValue");
env.remove("OTHERVAR");
env.put("VAR2", env.get("VAR1") + "suffix");
pb.directory(new File("myDir"));
Process p = pb.start();
Did you try to call your script directly, or did you specify a shell to use? You may need to specify the shell on your exec call if it's not specified (and processed) from the first line of the script.
From looking at your description, how you conclude the script didn't work:
I do not get any error messages but when I searched the folder, I saw
that script did not work. How can I fix it?
I conclude, the script creates a new file, and there is none, after starting from Java.
Maybe you assume, that the output of the script will, if sent to the current directory, end in the directory of the script, not in the directory where you started your Java application.
This might be the Desktop, if you start your class from the UI with an Icon as starter, it might be your home or project dir, if you compile the class from hand, or a directory, set up by your IDE, if you develop with eclipse or the like.
If your script writes to an absolute path like /tmp/script.out, you could verify fast, whether this might be your issue.
I compile java file by Runtime.exec("javac MyFrog.java");
It says no errors, doesn't output anything, but doesn't create MyFrog.class file.
if i write Runtime.exec("javac") it outputs to output some help text.
So I understand that program is working, but don't create class file. Permissions are ok.
javac -verbose should give you lot more information, specifically the directory where the file is created. Since you are able to recognize output help text without any parameters, I assume you are capturing the process's stderr and assume you are doing the same for stdout as well (though javac does not seem to write anything to stdout).
Where are you checking for the existence of the .class file? It is created in the same directory as the .java file. If MyFrog.java has a package declaration it will not be created in the package sub-dir; for that you have to use -d argument.
make sure that MyFrog.java is present in working directory
Try javac -verbose and make sure your classpath is set correct.
You can use ProcessBuilder or Runtime.exec() method to create new process,
String []cmd={"javac","Foo.java"};
Process proc=Runtime.getRuntime().exec(cmd);
proc.waitFor();
Or use ProcessBuilder
ProcessBuilder pb = new ProcessBuilder("javac.exe","-verbose", "Foo.java");
pb.redirectErrorStream(true);
Process p = pb.start();
p.waitFor();
InputStream inp=p.getInputStream();
int no=inp.read();
while(no!=-1)
{
System.out.print((char)no);
no=inp.read();
}
I always find this resource answers all questions about Java exec.