-1

From the man test pages:

-n STRING
    the length of STRING is nonzero

STRING equivalent to -n STRING

-z STRING the length of STRING is zero

Executing [ -n $foo ], [ -n ], [ -z $foo ], [ -z ], all return true. Is this just sloppy return value? An unset variable is not a STRING. The total omission of an expression is not either. And even if it WERE being somehow "coerced" into one, I'm disinclined to think it's length could be both zero and non-zero simultaneously.

Indeed, both

if [ -n ] && [ -z ]; then 
   echo 1; 
fi
# AND
if [ -n $foo ] && [ -z $foo ]; then 
   echo 1; 
fi

...both yield "1". Why? What's going on under the hood here?

NerdyDeeds
  • 121
  • 5

1 Answers1

4

The problem

You misunderstand how the test conditions are parsed.

First bash determines the number of arguments:

  • nothing between [ and ] is false
  • exactly one argument (which is not the empty argument) between them is always true, no matter the content of the argument; false in case of an empty argument ([ '' ])
  • only if there is more than one argument then shell looks at the content.

-z and -n require a second argument. As there is none in your case, they are not treated as -z / -n but just as any piece of content which results in true.

The solution

You have to quote your variables (as you should nearly always do). Then an empty variable is seen as an empty argument instead of just being removed completely.

Hauke Laging
  • 90,279