How to tell if a string is not defined in a Bash shell script How to tell if a string is not defined in a Bash shell script shell shell

How to tell if a string is not defined in a Bash shell script


I think the answer you are after is implied (if not stated) by Vinko's answer, though it is not spelled out simply. To distinguish whether VAR is set but empty or not set, you can use:

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fiif [ -z "$VAR" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

You probably can combine the two tests on the second line into one with:

if [ -z "$VAR" -a "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

However, if you read the documentation for Autoconf, you'll find that they do not recommend combining terms with '-a' and do recommend using separate simple tests combined with &&. I've not encountered a system where there is a problem; that doesn't mean they didn't used to exist (but they are probably extremely rare these days, even if they weren't as rare in the distant past).

You can find the details of these, and other related shell parameter expansions, the test or [ command and conditional expressions in the Bash manual.


I was recently asked by email about this answer with the question:

You use two tests, and I understand the second one well, but not the first one. More precisely I don't understand the need for variable expansion

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fi

Wouldn't this accomplish the same?

if [ -z "${VAR}" ]; then echo "VAR is not set at all"; fi

Fair question - the answer is 'No, your simpler alternative does not do the same thing'.

Suppose I write this before your test:

VAR=

Your test will say "VAR is not set at all", but mine will say (by implication because it echoes nothing) "VAR is set but its value might be empty". Try this script:

(unset VARif [ -z "${VAR+xxx}" ]; then echo "JL:1 VAR is not set at all"; fiif [ -z "${VAR}" ];     then echo "MP:1 VAR is not set at all"; fiVAR=if [ -z "${VAR+xxx}" ]; then echo "JL:2 VAR is not set at all"; fiif [ -z "${VAR}" ];     then echo "MP:2 VAR is not set at all"; fi)

The output is:

JL:1 VAR is not set at allMP:1 VAR is not set at allMP:2 VAR is not set at all

In the second pair of tests, the variable is set, but it is set to the empty value. This is the distinction that the ${VAR=value} and ${VAR:=value} notations make. Ditto for ${VAR-value} and ${VAR:-value}, and ${VAR+value} and ${VAR:+value}, and so on.


As Gili points out in his answer, if you run bash with the set -o nounset option, then the basic answer above fails with unbound variable. It is easily remedied:

if [ -z "${VAR+xxx}" ]; then echo "VAR is not set at all"; fiif [ -z "${VAR-}" ] && [ "${VAR+xxx}" = "xxx" ]; then echo "VAR is set but empty"; fi

Or you could cancel the set -o nounset option with set +u (set -u being equivalent to set -o nounset).


~> if [ -z $FOO ]; then echo "EMPTY"; fiEMPTY~> FOO=""~> if [ -z $FOO ]; then echo "EMPTY"; fiEMPTY~> FOO="a"~> if [ -z $FOO ]; then echo "EMPTY"; fi~> 

-z works for undefined variables too. To distinguish between an undefined and a defined you'd use the things listed here or, with clearer explanations, here.

Cleanest way is using expansion like in these examples. To get all your options check the Parameter Expansion section of the manual.

Alternate word:

~$ unset FOO~$ if test ${FOO+defined}; then echo "DEFINED"; fi~$ FOO=""~$ if test ${FOO+defined}; then echo "DEFINED"; fiDEFINED

Default value:

~$ FOO=""~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fi~$ unset FOO~$ if test "${FOO-default value}" ; then echo "UNDEFINED"; fiUNDEFINED

Of course you'd use one of these differently, putting the value you want instead of 'default value' and using the expansion directly, if appropriate.


Advanced bash scripting guide, 10.2. Parameter Substitution:

  • ${var+blahblah}: if var is defined, 'blahblah' is substituted for theexpression, else null is substituted
  • ${var-blahblah}: if var is defined, it is itself substituted, else'blahblah' is substituted
  • ${var?blahblah}: if var is defined, it is substituted, else thefunction exists with 'blahblah' as an error message.


to base your program logic on whether the variable $mystr is defined or not, you can do the following:

isdefined=0${mystr+ export isdefined=1}

now, if isdefined=0 then the variable was undefined, if isdefined=1 the variable was defined

This way of checking variables is better than the above answer because it is more elegant, readable, and if your bash shell was configured to error on the use of undefined variables (set -u), the script will terminate prematurely.


Other useful stuff:

to have a default value of 7 assigned to $mystr if it was undefined, and leave it intact otherwise:

mystr=${mystr- 7}

to print an error message and exit the function if the variable is undefined:

: ${mystr? not defined}

Beware here that I used ':' so as not to have the contents of $mystr executed as a command in case it is defined.