11

I want to understand the if else statement in sh scripting.

So I wrote the below to find out whether JAVA_HOME is set in the environment or not. I wrote the below script

#!/bin/sh
if [ $JAVA_HOME != "" ]
then
    echo $JAVA_HOME
else
    echo "NO JAVA HOME SET"
fi

This my output to env:

sh-3.2$ env

SHELL=/bin/csh
TERM=xterm
HOST=estilor
SSH_CLIENT=10.15.16.28 4348 22
SSH_TTY=/dev/pts/18
USER=asimonraj
GROUP=ccusers
HOSTTYPE=x86_64-linux
PATH=/usr/local/bin:/bin:/home/asimonraj/java/LINUXJAVA/java/bin:/usr/bin
MAIL=/var/mail/asimonraj
PWD=/home/asimonraj/nix
HOME=/home/asimonraj
SHLVL=10
OSTYPE=linux
VENDOR=unknown
LOGNAME=asimonraj
MACHTYPE=x86_64
SSH_CONNECTION=100.65.116.248 4348 100.65.116.127 22
_=/bin/env

But I get the below output:

sh-3.2$ ./test.sh
./test.sh: line 3: [: !=: unary operator expected
NO JAVA HOME SET

4 Answers 4

18

You're running into a stupid limitation of the way sh expands arguments. Line 3 of your script is being expanded to:

if [ != ]

Which sh can't figure out what to do with. Try this nasty hack on for size:

if [ x$JAVA_HOME != x ]

Both arguments have to be non-empty, so we'll just throw an x into both of them and see what happens.

Alternatively, there's a separate operator for testing if a string is non-empty:

if [ !-z $JAVA_HOME ]

(-z tests if the following string is empty.)

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

6 Comments

@Keith Thompson: @diskwuff describes the standard convention here. It also works if $JAVA_HOME is set to other things test will choke on, although I notice that bash is pretty lenient.
@reinierpost: Are you saying that the "x" prefix is the standard convention? It probably was at one time, but I don't think it's necessary today, and I rarely see it. The operands don't have to be non-empty, they just have to be single "words" (where a word can be the empty string). (It may be that some very old shells didn't distinguish between an argument of "" and no argument at all, but I'd be surprised if any shell in common current use had that problem.)
-1: [ x$JAVA_HOME != x ] is completely the wrong way to solve this problem; it causes other bugs. (Look at what happens if your JAVA_HOME contains a space, or, worse, a wildcard that matches content in the current directory... or, if the nullglob option is set, a wildcard character that doesn't match).
@reinierpost, that "standard convention" was created to work around bugs in 1970s-era shells. Those shells have been gone for decades. It's an antiquated convention, and should no longer be taught.
sh knows exactly what to do with [ != ]. It invokes the [ command with the arguments != and ], and the [ utility (whether builtin to the shell or the external command) knows exactly what to do with the arguments != and ]: it treats them as an error and reports the error. This is not a limitation of the way the shell expands arguments; it is simply the way it is done.
|
3
if [ -z $JAVA_HOME  ]  
then  
    echo $JAVA_HOME  
else  
    echo "NO JAVA HOME SET"  
fi

6 Comments

Use four-spaces to indent blocks of code, it makes them easier to read. (Or just highlight the code, and click the {} button.)
@OverZealous: I tried that but it is not working even pressing 4 times spacebar , i don't find any change in output preview.
Well, I'd fix it for you, but I'm required to make 6 non-whitespace character changes, and your example is fine. You have to have 4 extra spaces in front of each line, and remove the backticks. (Or just use the toolbar.)
@kracekumar: I get ./test.sh: line 2: [: -ne: unary operator expected NO JAVA HOME SET
@Abhishek Simon : In case you want to check it is empty, use -z switch.
|
3

The -n and -z options are tests that should be used here:

if [ -n "$JAVAHOME" ]; then
    echo "$JAVAHOME";
else
    echo "\$JAVAHOME not set";
fi

1 Comment

I'd suggest using single-quotes rather than double-quotes and escaping in the case where you don't want expansion to occur. Otherwise, looks good.
1

Note that if you want to determine if a variable is set, you probably do not want to use either if/else or test ([). It is more typical to do things like:

# Abort if JAVA_HOME is not set (or empty)
: ${JAVA_HOME:?JAVA_HOME is unset}

or

# report the value of JAVA_HOME, or a default value
echo ${JAVA_HOME:-default value}

or

# Assign JAVA_HOME if it is unset (or empty)
: ${JAVAHOME:=default value}

4 Comments

The echo case needs more quotes. Otherwise, this is the best answer I've seen here so far (the lack of quality is somewhat discouraging).
If JAVA_HOME contains path elements with spaces, there are more problems with the system than can be solved with double quotes!
Just because it would be bad practice to choose a filename or location that would trigger bugs in buggy programs is no excuse for those programs to be buggy.
Create a directory named var:bin in /usr. Install program foo in /usr/var:bin. Put /usr/var:bin in PATH. What is the bug that prevents the shell from being able to find foo in the PATH?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.