0

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.)

Lii
  • 11,553
  • 8
  • 64
  • 88
  • It's weird if this problem don't have a solution already, but I really couldn't find anything. – Lii Aug 24 '22 at 13:40
  • The executable file will be called exactly the same? If so, why don't you pass the location of said file as either an arg or a environment variable? `System#getProperty` and `System#getenv`, repectivelly. – Jetto Martínez Aug 24 '22 at 14:12
  • @JettoMartínez: That is a possibility... But a little inconvenient... – Lii Aug 24 '22 at 14:14

1 Answers1

1

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.

Robert
  • 7,394
  • 40
  • 45
  • 64
  • Hah! It does! Thanks! I was fooled by two things: Eclipse starts programs with an empty environment. And I was trying to start `mvn`, but you have to use `mvn.cmd` instead. – Lii Aug 24 '22 at 17:39
  • 1
    PS: Now days you can print the output of a process like this: `System.out.println(new String(process.getInputStream().readAllBytes()));` – Lii Aug 24 '22 at 17:40