Test if a variable is set in bash when using "set -o nounset"
BashShellUnixBash Problem Overview
The following code exits with a unbound variable error. How to fix this, while still using the set -o
nounset option?
#!/bin/bash
set -o nounset
if [ ! -z ${WHATEVER} ];
then echo "yo"
fi
echo "whatever"
Bash Solutions
Solution 1 - Bash
#!/bin/bash
set -o nounset
VALUE=${WHATEVER:-}
if [ ! -z ${VALUE} ];
then echo "yo"
fi
echo "whatever"
In this case, VALUE
ends up being an empty string if WHATEVER
is not set. We're using the {parameter:-word}
expansion, which you can look up in man bash
under "Parameter Expansion".
Solution 2 - Bash
You need to quote the variables if you want to get the result you expect:
check() {
if [ -n "${WHATEVER-}" ]
then
echo 'not empty'
elif [ "${WHATEVER+defined}" = defined ]
then
echo 'empty but defined'
else
echo 'unset'
fi
}
Test:
$ unset WHATEVER
$ check
unset
$ WHATEVER=
$ check
empty but defined
$ WHATEVER=' '
$ check
not empty
Solution 3 - Bash
How about a oneliner?
[ -z "${VAR:-}" ] && echo "VAR is not set or is empty" || echo "VAR is set to $VAR"
-z
checks both for empty or unset variable
Solution 4 - Bash
Assumptions:
$ echo $SHELL
/bin/bash
$ /bin/bash --version | head -1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)
$ set -o nounset
If you want a non-interactive script to print an error and exit if a variable is null or not set:
$ [[ "${HOME:?}" ]]
$ [[ "${IAMUNBOUND:?}" ]]
bash: IAMUNBOUND: parameter null or not set
$ IAMNULL=""
$ [[ "${IAMNULL:?}" ]]
bash: IAMNULL: parameter null or not set
If you don't want the script to exit:
$ [[ "${HOME:-}" ]] || echo "Parameter null or not set."
$ [[ "${IAMUNBOUND:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.
$ IAMNULL=""
$ [[ "${IAMUNNULL:-}" ]] || echo "Parameter null or not set."
Parameter null or not set.
You can even use [
and ]
instead of [[
and ]]
above, but the latter is preferable in Bash.
Note what the colon does above. From the docs:
> Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.
There is apparently no need for -n
or -z
.
In summary, I may typically just use [[ "${VAR:?}" ]]
. Per the examples, this prints an error and exits if a variable is null or not set.
Solution 5 - Bash
You can use
if [[ ${WHATEVER:+$WHATEVER} ]]; then
but
if [[ "${WHATEVER:+isset}" == "isset" ]]; then
might be more readable.
Solution 6 - Bash
While this isn't exactly the use case asked for above, I've found that if you want to use nounset
(or -u
) the default behavior is the one you want: to exit nonzero with a descriptive message.
It took me long enough to realize this that I figured it was worth posting as a solution.
If all you want is to echo something else when exiting, or do some cleanup, you can use a trap.
The :-
operator is probably what you want otherwise.