31

In Bash shell scripting, what is the difference (if any) between the following two statements?

  1. if [ -z "$1" ]
  2. if [ "$1" = "" ]

I have found myself writing the second one in some scripts, but then I read here that using -z achieves the same thing.

If there are problems using the second one, should we ignore that the first one looks a little better?

3

1 Answer 1

40

[ "$1" = "" ] and [ -z "$1" ] are exactly equivalent in bash and other POSIX-compliant shells. (Note that there must be a space on each side of the brackets, unless there is a non-word-constituent character like ;.)

[ is a shell built-in like any other; in fact it can also be spelled test (the only difference between the two is that [ requires a ] as the last argument). So if you run [ "$1" = "" ] with $1 expanding to -z, the test operator sees three arguments: -z, = and the empty string. Some older Bourne shells sometimes threw parse errors when an operand looked like an operator in this way, even if there was no ambiguity in the complete expression. I don't know if any version did in fact have trouble with this particular expression, but more complex expressions could throw them off. There may also have been versions that had trouble with empty words; these would not have supported [ -z "$1" ] either. A common shell idiom is [ x"$1" = x"" ]. It avoids any risk of having operands parsed as operators because no operator starts with a letter.

In ksh, bash and zsh, you can use the double bracket syntax, [[ -z $1 ]]. This newer syntax (it's from the late 1980s rather than the mid-1970s) eliminates the risk of having operands parsed as operators by using a special syntactic construct rather than an ordinary built-in. Operators must appear literally, unquoted within the double brackets, and you don't need to double quote variable expansions.

2
  • Fixed the typo with the missing space next to the bracket.
    – Johan
    Nov 7, 2010 at 17:24
  • -z was in the original test implementation in v7 (late 70s). See in-ulm.de/~mascheck/various/test for the corner cases where it doesn't work. I don't think any implementation ever had any problem with the empty string. test "" = "$1" would be reliable in any AFAIK. Jan 5, 2021 at 6:57

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.