tags:

views:

77

answers:

2

I've seen bash scripts test for non-zero length string two different ways. Most scripts use the -n option:

#!/bin/bash
# With the -n option
if [ -n "$var" ]; then
  # Do something when var is non-zero length
fi

But the -n option isn't really needed:

# Without the -n option
if [ "$var" ]; then
  # Do something when var is non-zero length
fi

Which is the better way?

Similarly, which is the better way for testing for zero-length:

if [ -z "$var" ]; then
  # Do something when var is zero-length
fi

or

if [ ! "$var" ]; then
  # Do something when var is zero-length
fi
A: 

use case/esac to test

case "$var" in
  "") echo "zero length";;
esac
ghostdog74
+5  A: 

The following table shows that whether a variable is quoted or not, whether you use single or double brackets and whether the variable contains only a space are the things that affect whether using a test with or without -n/-z is suitable for checking a variable.

       1a    2a    3a    4a    5a    6a    |1b    2b    3b    4b    5b    6b
       [     ["    [-n   [-n"  [-z   [-z"  |[[    [["   [[-n  [[-n" [[-z  [[-z"
unset: false false true  false true  true  |false false false false true  true
null : false false true  false true  true  |false false false false true  true
space: false true  true  true  true  false |true  true  true  true  false false
zero : true  true  true  true  false false |true  true  true  true  false false
char : true  true  true  true  false false |true  true  true  true  false false

If you want to know if a variable is non-zero length, do any of the following:

  • quote the variable in single brackets (column 2a)
  • use -n and quote the variable in single brackets (column 4a)
  • use double brackets with or without quoting and with or without -n (columns 1b - 4b)

This is the script that produced the table above.

#!/bin/bash
t () { echo -n "true  "; }
f () { echo -n "false "; }

unset u
n='' s=' ' z=0 c=c

echo '       1a    2a    3a    4a    5a    6a    |1b    2b    3b    4b    5b    6b'
echo '       [     ["    [-n   [-n"  [-z   [-z"  |[[    [["   [[-n  [[-n" [[-z  [[-z"'
for v in unset "null " space "zero " "char "
do
    i=${v:0:1}
    i=${!i}
    echo -en "$v: "
    [ $i ]        && t || f
    [ "$i" ]      && t || f
    [ -n $i ]     && t || f
    [ -n "$i" ]   && t || f
    [ -z $i ]     && t || f
    [ -z "$i" ]   && t || f
    echo -n "|"
    [[ $i ]]      && t || f
    [[ "$i" ]]    && t || f
    [[ -n $i ]]   && t || f
    [[ -n "$i" ]] && t || f
    [[ -z $i ]]   && t || f
    [[ -z "$i" ]] && t || f
    echo
done
Dennis Williamson
wow.. very good explanation! +1
jyzuz
Thanks! I've decided to adopt the style of "quote the variable in single brackets (column 2a)" IMO, the -n just adds noise and decreases readability.Similarly, for testing for zero-length or unset, I'll use [ ! "$var" ] instead of [ -z "$var" ].
AllenHalsey