32

I have seen the following technique used many times on many different shells, to test if a variable is empty:

if [ "x$1" = "x" ]; then 
    # Variable is empty
fi

Are there any advantages on using this over the more canonical if [ -z "$1" ]? Could it be a portability issue?

rahmu
  • 20,023

4 Answers4

25

Some historical shells implemented a very simple parser that could get confused by things like [ -n = "" ] where the first operand to = looks like an operator, and would parse this as [ -n = ] or cause a syntax error. In [ "x$1" = x"" ], the x prefix ensures that x"$1" cannot possibly look like an operator, and so the only way the shell can parse this test is by treating = as a binary operator.

All modern shells, and even most older shells still in operation, follow the POSIX rules which mandate that all test expressions of up to 4 words be parsed correctly. So [ -z "$1" ] is a proper way of testing if $1 is empty, and [ "$x" = "$y" ] is a proper way to test the equality of two variables.

Even some current shells can get confused with longer expressions, and a few expressions are actually ambiguous, so avoid using the -a and -o operators to construct longer boolean tests, and instead use separate calls to [ and the shell's own && and || boolean operators.

  • 4
    It's not only historical shells. Some ksh88 based shs on some commercial Unices still have the issue. See here for details. – Stéphane Chazelas Nov 27 '12 at 21:00
  • This statement is incorrect: [ -z "$1" ] is a proper way of testing if $1 is empty. sh -c '[ -z "$1" ]' ''; sh -c '[ -z "$1" ]' - both return 0, but in the second case $1 cannot be empty because it does not exist. – mikeserv Jul 29 '14 at 15:58
  • sh with the -c option is present, If there are arguments after the string, they are assigned to the positional parameters, starting with $0. not $1 – nelson Jan 20 '23 at 05:14
4

According to http://www.mpi-inf.mpg.de/~uwe/lehre/unixffb/quoting-guide.html, the -z test is unsafe in some implementations, presumably when "interesting" strings like "-o a=a" are tested.

3

The above tests will also cause an error if you run with "set -u" or "set -o nounset"

A more stable way to check for an empty variable would be to use parameter expansion:

MYVAR=${MYVAR:-"Bad Value"}

This method works for the traditional bourne shell, as well as ksh, and bash.

0
    function isBlank {
 valueNoSpaces=$(echo "$@" | tr -d ' ')

 if [  "$valueNoSpaces" == null ] || [ -z "$valueNoSpaces" ] 
 then
       echo true ;
 else
       echo ""  ;
 fi
}

#Test
if [ $(isBlank "      ") ] 
then
    echo "isBlank \"      \" : it's blank"
else
    echo " isBlank \"      \": it is not blank"
fi

if [ $(isBlank "abc") ] 

then
    echo "isBlank \"abc\" : it's blank"
else
    echo "isBlank \"abc\" :it is not blank"
fi

if [ $(isBlank null) ] 
then
      echo "isBlank null : it's blank"
else
    echo "isBlank null : it is not blank"
fi

if [ $(isBlank "") ] 
then
    echo "isBlank \"\" : it's blank"
else
    echo "isBlank \"\" : it is not blank"
fi

#Result
isBlank "      " : it's blank

isBlank "abc" :it is not blank

isBlank null : it's blank

isBlank "" : it's blank
steve
  • 21,892
  • 3
    Hi! I'm not sure how this answers the question, which asks why to use = versus -z, now how. – dhag Aug 28 '15 at 20:19