I'm trying to execute an external command from java code, but there's a difference I've noticed between Runtime.getRuntime().exec(...)
and new ProcessBuilder(...).start()
.
When using Runtime
:
Process p = Runtime.getRuntime().exec(installation_path +
uninstall_path +
uninstall_command +
uninstall_arguments);
p.waitFor();
the exitValue is 0 and the command is terminated ok.
However, with ProcessBuilder
:
Process p = (new ProcessBuilder(installation_path +
uninstall_path +
uninstall_command,
uninstall_arguments)).start();
p.waitFor();
the exit value is 1001 and the command terminates in the middle, although waitFor
returns.
What should I do to fix the problem with ProcessBuilder
?
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,
Runtime.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,
ProcessBuilder 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
ProcessBuilder b = new ProcessBuilder("C:\DoStuff.exe", "-arg1", "-arg2");
or alternatively
List<String> params = java.util.Arrays.asList("C:\DoStuff.exe", "-arg1", "-arg2");
ProcessBuilder b = new ProcessBuilder(params);