简体   繁体   中英

Java Runtime exec() does not resolve environment variable

If I run the following in a terminal I get the expected 123

$ /bin/sh
$ FOO=123
$ echo $FOO
123

Now I try to do the following with Java's Runtime's exec() :

String[] envp = { "FOO=123" };
String   cmd  = "echo $FOO";
Process  p    = Runtime.getRuntime().exec(cmd, envp);
java.io.BufferedReader reader = 
    new java.io.BufferedReader(
        new java.io.InputStreamReader(p.getInputStream()
    )
);
System.out.println(reader.readLine());

I expect to see 123 but instead I get $FOO .

What am I missing?

The following works under Windows.

String[] envp = { "FOO=123" };
String   cmd  = "cmd /c echo %FOO%";
Process  p    = Runtime.getRuntime().exec(cmd, envp);
p.waitFor(); 
java.io.BufferedReader reader = 
    new java.io.BufferedReader(
        new java.io.InputStreamReader(p.getInputStream()
    )
);
String line; 
while((line = reader.readLine()) != null) { 
    System.out.println(line);
}

What am I missing?

Firstly,

$ FOO=123

sets a shell variable. It is local to the shell. If you want a variable to be in the environment that child processes see, you must export it.

$ export FOO=123

But that's not the problem.

The real issue is the command string "echo $FOO" . The problem is that $FOO is shell syntax.... but when you run a command from Java using exec :

  • exec itself doesn't understand shell syntax, and
  • exec doesn't run the command in a shell.

So the parameter that is given to the echo command consists of the literal string $FOO ... and that is what it outputs.

There are three approaches to solving this:

  1. Interpolate the variable in Java; eg

     String[] cmd = {"echo", "123"}; Process p = Runtime.getRuntime().exec(cmd);

    or by doing repeated search / replace for things that look like variables. (But this only deals with environment variable interpolation, not other forms of shell substitution.)

  2. Assuming that you are doing something more complicated than echo , write the command that you are running to do its own interpolation of environment variables. (This is clunky...)

  3. Explicitly invoke the command in a shell; eg

     String[] envp = {"FOO=123"}; String[] cmd = {"/bin/sh", "-c", "echo $FOO"}; Process p = Runtime.getRuntime().exec(cmd, envp);

    Note that you can use any shell, and provide pretty much any shell-ism that can be expressed in a single shell command line.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM