Is there a platform-independent way in Java to start an external process that executes program which it finds using the system path?
It should work at least on Windows, Linux and Mac.
Normally your have to give the full path to an executable file, like this:
new ProcessBuilder("/some/path/execfile", "arg").start();
It is possible to start a program that is on the system path by starting a shell:
new ProcessBuilder("/bin/bash", "-c", "execfile", "arg").start();
But this is not portable between OS:s. (This is the solution that is given to this question.)
CodePudding user response:
ProcessBuilder
does use the $PATH
.
import java.io.*;
public class ProcessBuilderTest {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder(args);
pb.redirectErrorStream(true);
Process p = pb.start();
int exitCode = p.waitFor();
printStream(p.getInputStream());
printStream(p.getErrorStream());
System.out.println("Exit code: " exitCode);
}
static void printStream(InputStream stream) throws IOException {
try (BufferedReader br = new BufferedReader(new InputStreamReader(stream))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
}
}
Running this on MacOS:
robert@mac:~$ java ProcessBuilderTest.java ls *.java
ProcessBuilderTest.java
Exit code: 0
robert@mac:~$ java ProcessBuilderTest.java ls *.class
ls: cannot access '*.class': No such file or directory
Exit code: 2
robert@mac:~$ java ProcessBuilderTest.java which ls
/usr/local/opt/coreutils/libexec/gnubin/ls
Exit code: 0
robert@mac:~$
Same on Linux:
robert@linux:~$ java ProcessBuilderTest.java ls *.java
ProcessBuilderTest.java
Exit code: 0
robert@linux:~$ java ProcessBuilderTest.java ls *.class
ls: cannot access '*.class': No such file or directory
Exit code: 2
robert@linux:~$ java ProcessBuilderTest.java which ls
/usr/bin/ls
Exit code: 0
robert@linux:~$
I don't use Windows, so cannot test on that.