How to test if a variable is defined at all in Bash prior to version 4.2 with the nounset shell option?
Portable to all POSIX shells:
if [ -n "${foobar+1}" ]; then
echo "foobar is defined"
else
echo "foobar is not defined"
fi
Make that ${foobar:+1}
if you want to treat foobar
the same way whether it is empty or not defined. You can also use ${foobar-}
to get an empty string when foobar
is undefined and the value of foobar
otherwise (or put any other default value after the -
).
In ksh, if foobar
is declared but not defined, as in typeset -a foobar
, then ${foobar+1}
expands to the empty string.
Zsh doesn't have variables that are declared but not set: typeset -a foobar
creates an empty array.
In bash, arrays behave in a different and surprising way. ${a+1}
only expands to 1
if a
is a non-empty array, e.g.
typeset -a a; echo ${a+1} # prints nothing
e=(); echo ${e+1} # prints nothing!
f=(''); echo ${f+1} # prints 1
The same principle applies to associative arrays: array variables are treated as defined if they have a non-empty set of indices.
A different, bash-specific way of testing whether a variable of any type has been defined is to check whether it's listed in ${!PREFIX*}
. This reports empty arrays as defined, unlike ${foobar+1}
, but reports declared-but-unassigned variables (unset foobar; typeset -a foobar
) as undefined.
case " ${!foobar*} " in
*" foobar "*) echo "foobar is defined";;
*) echo "foobar is not defined";;
esac
This is equivalent to testing the return value of typeset -p foobar
or declare -p foobar
, except that typeset -p foobar
fails on declared-but-unassigned variables.
In bash, like in ksh, set -o nounset; typeset -a foobar; echo $foobar
triggers an error in the attempt to expand the undefined variable foobar
. Unlike in ksh, set -o nounset; foobar=(); echo $foobar
(or echo "${foobar[@]}"
) also triggers an error.
Note that in all situations described here, ${foobar+1}
expands to the empty string if and only if $foobar
would cause an error under set -o nounset
.
To sum up with Gilles' answer I made up my following rules:
- Use
[[ -v foobar ]]
for variables in Bash version >= 4.2. - Use
declare -p foobar &>/dev/null
for array variables in Bash version < 4.2. - Use
(( ${foo[0]+1} ))
or(( ${bar[foo]+1} ))
for subscripts of indexed (-a
) and keyed (-A
) arrays (declare
), respectively. Options 1 and 2 don't work here.
I use the same technique for all variables in bash, and it works, e.g.:
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"
outputs:
foobar is unset
whilst
foobar=( "val" "val2" )
[ ${foobar} ] && echo "foobar is set" || echo "foobar is unset"
outputs:
foobar is set