0

So I have a java process that is doing some automation. One of the things it has to do is find the JDK home on random machines.

So I wrote a shell script to try and find the JDK home assuming that javac is on the path.

While testing this shell script locally I came across some rather strange behavour which I would like to understand.

The strange behaviour boils down to the which command behaving rather oddly. The snippet of the script that I am at a loss to explain starts with

#/bin/sh
...
if [ -z "$JAVA_HOME" ]; then
    javac -version
    which javac || echo "rv=$?"
    javaExecutable="`which javac`"
    ...

(I added the javac -version and which javac || echo "rv=$?" just to check I had a valid PATH in the forked process)

If I use sh -x to start the forked process then I get the following output:

+ '[' -z '' ']'               
+ javac -version              
javac 1.8.0_11                
+ which javac        
+ echo rv=1                   
rv=1                          
++ which javac                
+ javaExecutable=

If I replace which with the following function

_which() {
    oldIFS="$IFS"
    IFS=':'
    for p in $PATH
    do
        if [ -x "$p/$1" ]; then
            echo "$p/$1"
            IFS="$oldIFS"
            return 0
        fi
    done
    IFS="$oldIFS"
    return 1
}

Then everything works as I would expect.

If I invoke my original script from the command line directly... everything works

If I invoke my original script via ssh localhost sh -x PathToScript... everything works

1 Answers1

0

So I found the solution to this one....

So basically how my Java process was launching the script was partly to blame... and also some other strangeness.

My Java process was clearing the environment to get something "sane"...

So the Java code looks like

    ProcessBuilder p = new ProcessBuilder(new String[]{
            "sh",
            "-x",
            "pathToScript.sh"
    }).redirectErrorStream(
            true).redirectOutput(ProcessBuilder.Redirect.INHERIT);
    p.environment().clear();
    p.start();

So what would happen is that sh would build up it's PATH locally but not export it.

When I changed my script from

javaExecutable="`which javac`"

to either

export PATH
javaExecutable="`which javac`"

or

javaExecutable="`PATH="$PATH" which javac`"

Then it all started to work

Recording this for posterity as it took a while to trace the root cause to my own stupidity (which was for a good reason elsewhere in the code)

  • in your script use export PATH=$PATH:/directory_path_of_jdk – c4f4t0r Jul 18 '14 at 13:07
  • @c4f4t0r I think you mis-understand the issue. When `which javac` is being run the only thing we know is that `javac` is on the shell's `PATH` but due to the way the shell process is invoked, the shell *process* environment does not have a `PATH` so `which` is exiting with `1` as there is no `javac` on its `PATH`. By adding `export PATH="$PATH"` I ensure that the forked `which` has a `PATH` and hence can find the same `javac` as the shell was – Stephen Connolly Jul 18 '14 at 13:32
  • And this whole script is being used *to find the unknown JDK home path* so we cannot hard-code the path... if we could hard-code it we wouldn't be running this script in the first place! – Stephen Connolly Jul 18 '14 at 13:33