Test for non-zero length string in Bash: [ -n "$var" ] or [ "$var" ] Test for non-zero length string in Bash: [ -n "$var" ] or [ "$var" ] bash bash

Test for non-zero length string in Bash: [ -n "$var" ] or [ "$var" ]


Edit: This is a more complete version that shows more differences between [ (aka test) and [[.

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  truenull | false false true  false true  true | false false false false true  truespace| false true  true  true  true  false| true  true  true  true  false falsezero | true  true  true  true  false false| true  true  true  true  false falsedigit| true  true  true  true  false false| true  true  true  true  false falsechar | true  true  true  true  false false| true  true  true  true  false falsehyphn| true  true  true  true  false false| true  true  true  true  false falsetwo  | -err- true  -err- true  -err- false| true  true  true  true  false falsepart | -err- true  -err- true  -err- false| true  true  true  true  false falseTstr | true  true  -err- true  -err- false| true  true  true  true  false falseFsym | false true  -err- true  -err- false| true  true  true  true  false falseT=   | true  true  -err- true  -err- false| true  true  true  true  false falseF=   | false true  -err- true  -err- false| true  true  true  true  false falseT!=  | true  true  -err- true  -err- false| true  true  true  true  false falseF!=  | false true  -err- true  -err- false| true  true  true  true  false falseTeq  | true  true  -err- true  -err- false| true  true  true  true  false falseFeq  | false true  -err- true  -err- false| true  true  true  true  false falseTne  | true  true  -err- true  -err- false| true  true  true  true  false falseFne  | false true  -err- true  -err- 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)

Notice in column 1a starting at the row labeled "two" that the result indicates that [ is evaluating the contents of the variable as if they were part of the conditional expression (the result matches the assertion implied by the "T" or "F" in the description column). When [[ is used (column 1b), the variable content is seen as a string and not evaluated.

The errors in columns 3a and 5a are caused by the fact that the variable value includes a space and the variable is unquoted. Again, as shown in columns 3b and 5b, [[ evaluates the variable's contents as a string.

Correspondingly, for tests for zero-length strings, columns 6a, 5b and 6b show the correct ways to do that. Also note that any of these tests can be negated if negating shows a clearer intent than using the opposite operation. For example: if ! [[ -n $var ]].

If you're using [, the key to making sure that you don't get unexpected results is quoting the variable. Using [[, it doesn't matter.

The error messages, which are being suppressed, are "unary operator expected" or "binary operator expected".

This is the script that produced the table above.

#!/bin/bash# by Dennis Williamson# 2010-10-06, revised 2010-11-10# for http://stackoverflow.com/q/3869072# designed to fit an 80 character terminaldw=5    # description column widthw=6     # table column widtht () { printf '%-*s' "$w" " true"; }f () { [[ $? == 1 ]] && printf '%-*s' "$w" " false" || printf '%-*s' "$w" " -err-"; }o=/dev/nullecho '     | 1a    2a    3a    4a    5a    6a   | 1b    2b    3b    4b    5b    6b'echo '     | [     ["    [-n   [-n"  [-z   [-z" | [[    [["   [[-n  [[-n" [[-z  [[-z"'echo '-----+------------------------------------+------------------------------------'while read -r d tdo    printf '%-*s|' "$dw" "$d"    case $d in        unset) unset t  ;;        space) t=' '    ;;    esac    [ $t ]        2>$o  && t || f    [ "$t" ]            && t || f    [ -n $t ]     2>$o  && t || f    [ -n "$t" ]         && t || f    [ -z $t ]     2>$o  && t || f    [ -z "$t" ]         && t || f    echo -n "|"    [[ $t ]]            && t || f    [[ "$t" ]]          && t || f    [[ -n $t ]]         && t || f    [[ -n "$t" ]]       && t || f    [[ -z $t ]]         && t || f    [[ -z "$t" ]]       && t || f    echodone <<'EOF'unsetnullspacezero    0digit   1char    chyphn   -ztwo     a bpart    a -aTstr    -n aFsym    -h .T=      1 = 1F=      1 = 2T!=     1 != 2F!=     1 != 1Teq     1 -eq 1Feq     1 -eq 2Tne     1 -ne 2Fne     1 -ne 1EOF


It is better to use the more powerful [[ as far as Bash is concerned.

Usual cases

if [[ $var ]]; then   # var is set and it is not emptyif [[ ! $var ]]; then # var is not set or it is set to an empty string

The above two constructs look clean and readable. They should suffice in most cases.

Note that we don't need to quote the variable expansions inside [[ as there is no danger of word splitting and globbing.

To prevent shellcheck's soft complaints about [[ $var ]] and [[ ! $var ]], we could use the -n option.

Rare cases

In the rare case of us having to make a distinction between "being set to an empty string" vs "not being set at all", we could use these:

if [[ ${var+x} ]]; then           # var is set but it could be emptyif [[ ! ${var+x} ]]; then         # var is not setif [[ ${var+x} && ! $var ]]; then # var is set and is empty

We can also use the -v test:

if [[ -v var ]]; then             # var is set but it could be emptyif [[ ! -v var ]]; then           # var is not setif [[ -v var && ! $var ]]; then   # var is set and is emptyif [[ -v var && -z $var ]]; then  # var is set and is empty

Related posts and documentation

There are a plenty of posts related to this topic. Here are a few:


Here are some more tests

True if string is not empty:

[ -n "$var" ][[ -n $var ]]test -n "$var"[ "$var" ][[ $var ]](( ${#var} ))let ${#var}test "$var"

True if string is empty:

[ -z "$var" ][[ -z $var ]]test -z "$var"! [ "$var" ]! [[ $var ]]! (( ${#var} ))! let ${#var}! test "$var"