Test if a variable is set in Bash when using "set -o nounset"

The following code exits with a unbound variable error. How can I fix this, while still using the set -o nounset option?

#!/bin/bash


set -o nounset


if [ ! -z ${WHATEVER} ];
then echo "yo"
fi


echo "whatever"
63256 次浏览
#!/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".

You can use

if [[ ${WHATEVER:+$WHATEVER} ]]; then

but

if [[ "${WHATEVER:+isset}" == "isset" ]]; then

might be more readable.

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

Use 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

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 documentation:

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.

While this isn't exactly the use case asked for, 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.

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.