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"
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"
#!/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 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.
You can use
if [[ ${WHATEVER:+$WHATEVER} ]]; then
but
if [[ "${WHATEVER:+isset}" == "isset" ]]; then
might be more readable.
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.
To me, most of the answers are at best confusing, not including a test matrix. They also often do not address the scenario where variable contains the defaulting value.
The solution from l0b0 is the only readable, testable (and correct in respect to the actual question IMO), but it is unclear if inverting/reordering the tests to simplify the logic produces correct result. I minified hirs solution
The (already minified) contrast solution from Aleš, exposes the difference of a variable being declared but undefined. The one or the other might fit your scenario.
#!/bin/bash -eu
check1() {
if [[ -n "${WHATEVER-}" ]]; then
echo 'something else: not empty'
elif [[ "${WHATEVER+defined}" = defined ]]; then
echo 'something else: declared but undefined'
else
echo 'unset'
fi
}
check2() {
if [[ "${WHATEVER+defined}" != "defined" ]]; then
echo 'unset'
else
echo "something else"
fi
}
check3() {
if [[ "${WHATEVER-defined}" = defined ]]; then
echo 'unset'
else
echo 'something else'
fi
}
check4() {
if [[ ! ${WHATEVER+$WHATEVER} ]]; then
echo 'unset'
else
echo 'something else'
fi
}
echo
echo "check1 from l0b0"
unset WHATEVER
check1
WHATEVER=
check1
WHATEVER=' '
check1
WHATEVER='defined'
check1
echo
echo "check2 prove simplification keeps semantics"
unset WHATEVER
check2
WHATEVER=
check2
WHATEVER=' '
check2
WHATEVER='defined'
check2
echo
echo "check3 other promising operator?"
unset WHATEVER
check3
WHATEVER=
check3
WHATEVER=' '
check3
WHATEVER='defined'
check3
echo
echo "check4 other interesting suggestion, from aleš"
unset WHATEVER
check4
WHATEVER=
check4
WHATEVER=' '
check4
WHATEVER='defined'
check4
Check1
and Check2
behave identicallyCheck3
is plainly wrongCheck4
: correct, depending on what you consider a declared/defined variable.check1 from l0b0
unset
something else: declared but undefined
something else: not empty
something else: not empty
check2 prove simplification keeps semantics
unset
something else
something else
something else
check3 other promising operator?
unset
something else
something else
unset
check4 other interesting suggestion, from aleš
unset
unset
something else
something else