Search code examples
javabashprocessbuilder

Loading all env variables with processbuilder


I want to load the variables I have defined in the .bashrc file prior to the execution of a script from a java code. The script is executed via the ProcessBuilder. On the web, I see that the command array should be started with bash -c as below:

String[] cmdline = {"/bin/bash", "-c", "python", "/home/mahmood/temp.py"};
final ProcessBuilder pb = new ProcessBuilder(cmdline);
pb.command(cmdline);
pb.redirectOutput(Redirect.INHERIT);
final Process p = pb.start();
int exitCode = p.waitFor();
if (exitCode != 0) {
   throw new IOException("... python failed :( \n");
}

Indeed the waitFor never returns! If I drop the bash -c, then the exitCode will be non-zero since the variables have not been loaded.

Please note that there is not a single variable in the .bashrc. Can I fix the problem with ProcessBuilder or there is a better option for that?


Solution

  • Bash has to be invoked as an interactive shell to read and execute commands from ~/.bashrc. When running bash -c command you're executing command in a non-interactive shell. To run interactively (and read .bashrc), just add -i:

    String[] cmdline = {"/bin/bash", "-ic", "python /home/mahmood/temp.py"};
    

    Also, note that the command string (python /path/to/file) has to be specified as a single word (notice single quotes when invoked from shell):

    bash -ic 'python /home/mahmood/temp.py'
    

    or otherwise, bash will execute python (the first word) interactively (not running the script) -- and that's the reason your waitFor never returns.


    Since running an interactive shell just to load some environment variables from .bashrc might be an overkill, you could extract the variables of interest in a separate file, for example:

    export var1=val1
    export var2='val 2'
    ...
    

    and then source that file just before running your python script:

    String[] cmdline = {"/bin/bash", "-c", ". /path/to/envfile; python /home/mahmood/temp.py"};