2

Code:

#!/bin/bash

EXISTS=""

echo ${#EXISTS} #print size of string

if [ -n $EXISTS ]; then
    echo "It exists!"
else
    echo "It is empty."
fi

if [ -z $EXISTS ]; then
    echo "It is empty."
else
    echo "It exists!"
fi

Output:

0
It exists!
It is empty.

From man bash:

-z string

True if the length of string is zero.

-n string

True if the length of string is non-zero.

Could someone explain this behavior of -n to me, and why it doesn't agree with -z? Thanks!

6
  • So I just realized this is more about the brackets - this works as expected with double brackets.
    – jdf
    Commented Jun 18, 2015 at 18:20
  • It is a bit of both. See the answer and my comment. Commented Jun 18, 2015 at 18:23
  • 1
    @EtanReisner your comment was super helpful. Thanks!
    – jdf
    Commented Jun 18, 2015 at 18:25
  • 1
    It's almost better to ignore [ and always use test (or even better, use [[ ... ]] when available and POSIX compatibility isn't a concern). You're less likely to be surprised by how the arguments to test are handled (because it actually looks like a command), and you don't need the ridiculous final ] argument whose only purpose is to further the illusion that [ is some sort of syntax.
    – chepner
    Commented Jun 18, 2015 at 18:31
  • 1
    Didn't we tell you to use quotes on your last question on this topic? Commented Jun 18, 2015 at 18:36

2 Answers 2

4

Quote the variable or better use [[...]] in BASH:

if [[ -n $EXISTS ]]; then echo "It exists!"; else echo "It is empty."; fi

It will print:

It is empty.

Similarly:

if [ -n "$EXISTS" ]; then echo "It exists!"; else echo "It is empty."; fi
It is empty.
1
  • 4
    Specifically this is because when $EXISTS is unquoted and the shell expands the variable in [ -n $EXISTS ] it becomes [ -n ] which is interpreted by [/test as [ -n -n ] (see the man page) whereas [[ doesn't have that empty variable problem and the quotes make it see [ -n '' ]. Commented Jun 18, 2015 at 18:23
3
EXISTS=""
if [ -n $EXISTS ]; then
    ...
fi

The behavior of [ ... ] depends on the number of arguments before the closing ].

If there's exactly one argument, it tests whether that argument is non-empty. Since the string "-n" is non-empty, [ -n ] is true. -n is interpreted as an operator only if it's followed by another argument.

To fix this, quote the argument so it's interpreted as a single empty argument, rather than as no argument:

if [ -n "$EXISTS" ]; then
    ...
fi

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