0

I'm trying to get the full path of system programs using the following Java code:

import java.io.BufferedReader;
import java.io.InputStreamReader;

public class PathExtractor {

    public static void main(String[] args) throws Exception {
        ProcessBuilder processBuilder = new ProcessBuilder("which", "mvn");
        processBuilder.redirectErrorStream(true);
        Process process = processBuilder.start();
        process.waitFor();
        try (BufferedReader in = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
            System.out.println(in.readLine());
        }
    }
}

When compiled and run from the command line, the expected output is printed out:

/usr/local/bin/mvn

However, when run within Eclipse, I get exit value 1 with the following output:

null

After a bit of research, I found a similar question, with this answer suggesting to start a shell to run the previous command:

new ProcessBuilder("/bin/sh", "-c", "which mvn")

Unfortunately the command still fails with a null output. Note that on a Windows machine simply using new ProcessBuilder("where", "mvn") has the desired effect.

How can I determine the path of programs programmatically from within Eclipse?

Pyves
  • 6,333
  • 7
  • 41
  • 59
  • What operating system? This code runs OK on macOS – greg-449 Mar 31 '19 at 07:03
  • Well, funnily enough, it's macOS as well for me. Slightly old version, El Capitan, but I wouldn't expect that to matter too much. Does it work as well for you with executables stored in less "standard" locations, for instance a Ruby gems? Another observation is that when I run the command with zsh shell ("/bin/zsh", "-c", "which mvn"), it fails but I do get a "mvn not found" error rather than "null". – Pyves Mar 31 '19 at 07:31
  • 1
    This code returns `null` for anything that isn't on the current PATH. `which` only searches the path. – greg-449 Mar 31 '19 at 07:36
  • So I'm guessing that there's no way to do what I'm asking for? Eclipse will generally not be started with the PATH the user defined in their profile in macOS. – Pyves Mar 31 '19 at 07:58
  • I'm also surprised `null` is returned rather than a helpful error message. It's as if `which` itself failed rather than reporting that it did not find the command. – Pyves Mar 31 '19 at 07:59
  • The `process.waitFor()` call returns the 'exit value' of the program, this is 0 when 'which' found the program and 1 when it didn't - you get null when the exit code is 1. When running a program from Eclipse you can specify environment variables in the 'Run Configuration' for the program – greg-449 Mar 31 '19 at 08:37
  • In fact, the reason it prints `null` is because a different command is being used in the `sh` shell, `/usr/bin/which`, and that seems to be its behaviour. When invoking through `zsh`, `which` is a shell builtin, printing messages such as "mvn not found". That's one bit of confusion solved. Back to the core problem, as I'm building a plugin, making users alter their launch configurations isn't a great experience. However, passing the login option `-l` to `bash` seems to do the trick: `new ProcessBuilder("/bin/bash", "-l", "-c", "which mvn")`. Will experiment some more and wrap up in an answer. – Pyves Mar 31 '19 at 09:29

1 Answers1

0

After some digging, I managed to programmatically get full paths of external programs from within Eclipse with the following command:

new ProcessBuilder("/bin/bash", "-l", "-c", "which mvn")

The -l (or --login) flag is the key to the solution. According to the bash man page:

Make bash act as if it had been invoked as a login shell

[...]

When bash is invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first reads and executes commands from the file /etc/profile, if that file exists. After reading that file, it looks for ~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and executes commands from the first one that exists and is readable.

In other words, this will allow the external programme to pick up the PATH variable from one of the standard locations, even though it may be set to a different value in Eclipse itself.

Pyves
  • 6,333
  • 7
  • 41
  • 59