The various overloads of Runtime.getRuntime().exec(...) take either an array of strings or a single string. The single-string overloads of exec() will tokenise the string into an array of arguments, before passing the string array onto one of the exec() overloads that takes a string array. The ProcessBuilder constructors, on the other hand, only take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument. Either way, the arguments obtained are then joined up into a string that is passed to the OS to execute.
So, for example, on Windows,
CopyRuntime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");
will run a DoStuff.exe program with the two given arguments. In this case, the command-line gets tokenised and put back together. However,
CopyProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
will fail, unless there happens to be a program whose name is DoStuff.exe -arg1 -arg2 in C:\. This is because there's no tokenisation: the command to run is assumed to have already been tokenised. Instead, you should use
CopyProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");
or alternatively
CopyList<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
Answer from Luke Woodward on Stack OverflowThe various overloads of Runtime.getRuntime().exec(...) take either an array of strings or a single string. The single-string overloads of exec() will tokenise the string into an array of arguments, before passing the string array onto one of the exec() overloads that takes a string array. The ProcessBuilder constructors, on the other hand, only take a varargs array of strings or a List of strings, where each string in the array or list is assumed to be an individual argument. Either way, the arguments obtained are then joined up into a string that is passed to the OS to execute.
So, for example, on Windows,
CopyRuntime.getRuntime().exec("C:\DoStuff.exe -arg1 -arg2");
will run a DoStuff.exe program with the two given arguments. In this case, the command-line gets tokenised and put back together. However,
CopyProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe -arg1 -arg2");
will fail, unless there happens to be a program whose name is DoStuff.exe -arg1 -arg2 in C:\. This is because there's no tokenisation: the command to run is assumed to have already been tokenised. Instead, you should use
CopyProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");
or alternatively
CopyList<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);
There are no difference between ProcessBuilder.start() and Runtime.exec() because implementation of Runtime.exec() is:
Copypublic Process exec(String command) throws IOException {
return exec(command, null, null);
}
public Process exec(String command, String[] envp, File dir)
throws IOException {
if (command.length() == 0)
throw new IllegalArgumentException("Empty command");
StringTokenizer st = new StringTokenizer(command);
String[] cmdarray = new String[st.countTokens()];
for (int i = 0; st.hasMoreTokens(); i++)
cmdarray[i] = st.nextToken();
return exec(cmdarray, envp, dir);
}
public Process exec(String[] cmdarray, String[] envp, File dir)
throws IOException {
return new ProcessBuilder(cmdarray)
.environment(envp)
.directory(dir)
.start();
}
So code:
CopyList<String> list = new ArrayList<>();
new StringTokenizer(command)
.asIterator()
.forEachRemaining(str -> list.add((String) str));
new ProcessBuilder(String[])list.toArray())
.environment(envp)
.directory(dir)
.start();
should be the same as:
CopyRuntime.exec(command)
Thanks dave_thompson_085 for comment
java - ProcessBuilder vs Runtime.exec() - Stack Overflow
Disadvantages of using Runtime.exec()?
java - Order a Runtime exec and a ProcessBuilder.start? - Stack Overflow
Frequent 'processbuilder' Questions - Stack Overflow
I'm working with some legacy code and have to remake a software module. The module previously used Runtime.exec() for things such as making a directory, removing a directory, unzipping a file, and copying files. The software runs on Linux servers and most probably will always run on a Linux server.
Now that I'm making the module from scratch, I'm thinking of using native Java functions for accomplishing all this. Keeping the project requirements/dependencies aside for a moment, is there any advantage/disadvantage of doing it this way?
Well you can use DefaultExecutor from Apache Commons Exec library to execute commands but it internally uses java.lang.Runtime and java.lang.Process.
I would suggest you to use this library over Runtime because Apache Command Execution APIs are more sophisticated, and provide all and more features than Java Runtime. It also handles exit Values.
There are quite a few possible ways; but I can't call any of them desirable without understanding your motivation.
For example, write a program in C or Perl or whatever language and have it listen on a socket. Your java program can then connect to the socket and send a message with the name of the program to spawn, arguments etc. The receiver program can go ahead and spawn this.
Basically the Runtime.exec starts a new process in the OS asynchronously, and there is no guarantee that it is finished before your new process is started. Theoretically you sould wait for the taskkill to return with a SUCCESS result and start your new job only after that. According to its documentation taskkill will tell you with 0 return code if it has successfully killed its suspect.
The issue is not priority related, since both of them will have the default priority. A possible issue is that Runtime.exec using a String will have to parse the input and then execute the command, while ProcessBuild will execute the given command without the needed parsing logic. Because of this you can see a small delay and you need the waitFor to work as intended. You can eliminate this delay by using the String[] version of the Runtime.exec.
Also note that the threads are scheduled by the system scheduler and the execution order is unpredictable, see Java thread unpredictable.