3

I have a problem with adding a path to the environment of a process using processbuider. I have no clue why the process is ignoring the environment. Here is my example:

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Map;


public class main {

    public static void main(String [ ] args) {
         try {
            String s = null;


            ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "fsl");
            Map<String, String> env;
            env = pb.environment();
            env.put("FSLDIR", "/usr/local/fsl/bin/");

            Process p = pb.start();

            BufferedReader stdInput = new BufferedReader(new
                    InputStreamReader(p.getInputStream()));

            BufferedReader stdError = new BufferedReader(new
                    InputStreamReader(p.getErrorStream()));

            System.out.println("Process p:");

            // read the output from the command
            while ((s = stdInput.readLine()) != null) {
                System.out.println(s);
            }
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }

            //////////*********\\\\\\\\\\\

            ProcessBuilder pb2 = new ProcessBuilder("/usr/local/fsl/bin/fsl");

            s = null;
            Process p2 = pb2.start();

            stdInput = new BufferedReader(new
                    InputStreamReader(p2.getInputStream()));

            stdError = new BufferedReader(new
                    InputStreamReader(p2.getErrorStream()));

            System.out.println("Process p2:");

            // read the output from the command
            while ((s = stdInput.readLine()) != null) {
                System.out.println(s);
            }
            while ((s = stdError.readLine()) != null) {
                System.out.println(s);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }


    }
}

Output:

Process p:

/bin/bash: fsl: command not found

Process p2:

DISPLAY is not set. Please set your DISPLAY environment variable!

And you see FSL wants some more variables to be set. That is why p2 is not an option.

4
  • What environment do you talk about in the process is ignoring the environment? Commented Dec 21, 2016 at 13:33
  • its that of pb.environment() System.out.println(env); actually shows that the directory got added Commented Dec 21, 2016 at 13:39
  • 2
    The error message reported by the process p is logical because bash cannot find the comand fsl. Something like FSLDIR=/usr/local/fsl/bin/ has no effect in the behaviour of bash -- It is the PATH variable which should have to be changed in order to make bash find the fsl command. Commented Dec 21, 2016 at 14:16
  • thx Jdamian, it worked. Commented Dec 26, 2016 at 14:54

1 Answer 1

2

As Jdamian said, Bash searches the directories in the PATH environment variable to find binaries - Bash does not look for your FSLDIR variable, nor will it treat the values of arbitrary variables as executables.

The first thing you should always do when running into issues with a process library (e.g. ProcessBuilder in Java, subprocess in Python), is try to replicate the issue directly in the shell. If you run fsl or /bin/bash -c fsl in your shell you'll likely see the same error (if you don't you're not running your Java binary the same way as your shell) which confirms the issue is not related to Java.

Once you've confirmed that it's just a question of how to fix it. If you intend for fsl to be always available add its containing directory to your PATH in your ~/.bashrc file:

export PATH="$PATH:/usr/local/fsl/bin"

If you just want it available in your Java binary, modify the PATH in-process:

// notice there's no need for `bash -c`
ProcessBuilder pb = new ProcessBuilder("fsl");
pb.environment().put("PATH",
                     "/usr/local/fsl/bin" + File.pathSeparator + System.getenv("PATH"));

In practice however, your code will often be much more maintainable and easier to work with if you don't modify the PATH and instead simply always invoke external processes by their absolute path, like your second example:

ProcessBuilder pb = new ProcessBuilder("/usr/local/fsl/bin/fsl");

These two commands are (roughly) equivalent, but the latter is far more clear, and less likely to introduce confusing bugs.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.