Reputation: 3869
I'm writing a bash function to check for blank or unset variables.
function exit_if_var_does_not_exist {
TMP_NAME=$1
TMP_VALUE=`echo $TMP_NAME`
if [ -z ${TMP_VALUE+x} ]; then
echo "Variable [${TMP_NAME}] is unset. Exiting."
exit 1
else
if [ ${TMP_VALUE} = "" ]; then
echo "Variable [${TMP_NAME}] is set to ''. Exiting."
exit 1
fi
fi
echo "Variable [${TMP_NAME}] is set to ${TMP_VALUE}"
}
VAR=Test
exit_if_var_does_not_exist VAR
BLANK=
exit_if_var_does_not_exist BLANK
This does not give me the expected output in TMP_VALUE. Can someone please help me with what I'm missing here?
-bash-3.2$ ./x.sh
Variable [VAR] is set to VAR
Variable [BLANK] is set to BLANK
Upvotes: 4
Views: 387
Reputation: 2806
Another way:
exit_if_var_does_not_exist() {
if ! (set -u; : "${!1}") >/dev/null 2>&1; then
printf 'Variable [%s] is unset. Exiting.\n' "$1"
exit 1
elif [ -z "${!1}" ]; then
printf "Variable [%s] is set to ''. Exiting.\n" "$1"
exit 1
fi
printf 'Variable [%s] is set to %s\n' "$1" "${!1}"
}
If you don't need to separate the two error messages:
exit_if_var_does_not_exist() {
: "${!1:?$1 is unset or blank}"
printf 'Variable [%s] is set to %s\n' "$1" "${!1}"
}
Upvotes: 1
Reputation: 80921
The problem with the empty test block is that at no point in this snippet do you ever actually get the value of the originally named variable.
When you use TMP_NAME=$1
you assign the name of the input variable to TMP_NAME
and then
TMP_VALUE=`echo $TMP_NAME`
just assigns that name to TMP_VALUE
. Effectively you just ran TMP_VALUE=$1
.
So you aren't testing for whether the originally named variable has contents anywhere here.
To do that you need to use indirect expansion.
Namely TMP_VALUE=${!TMP_NAME}
or TMP_VALUE=${!1}
.
Side comment your "unset" test block at the top can never trigger.
TMP_VALUE
can never be unset because you assign to it. Even TMP_VALUE=
marks the variable as "set". So that bit is useless. Though, and thank David C. Rankin for trying long enough to make me think of this, you can use an indirect expansion trick to make this work.
[ -z "${!TMP_NAME+x}" ]
will return true for any set variable named in TMP_NAME
and false for an unset variable.
That all said if what you want to do is error if a variable is unset or blank the shell has you covered. Just use
: "${VAR:?Error VAR is unset or blank.}" || exit 1
Finally, as David C. Rankin points out inside [
you need to quote expansions that might disappear when they change the meaning of tests (you see this in the -z
test above) as well as here.
So [ ${TMP_VALUE} = "" ]
needs to be [ "${TMP_VALUE}" = "" ]
because is TMP_VALUE
is empty the first version would become a syntax error because [ = "" ]
isn't a valid invocation of test
/[
.
Upvotes: 3
Reputation: 84521
I'm not sure this will work for all cases, but try:
#!/bin/bash
function exit_if_var_does_not_exist {
local TMP_NAME=$1
local TMP_VALUE="${!TMP_NAME}"
[ -z "${!TMP_NAME}" ] && {
echo "Variable [${TMP_NAME}] is unset. Exiting."
return 1
}
[ "$TMP_VALUE" = "" ] && {
echo "Variable [${TMP_NAME}] is set to ''. Exiting."
return 1
}
echo "Variable [${TMP_NAME}] is set to ${TMP_VALUE}"
}
VAR=Test
exit_if_var_does_not_exist VAR
# BLANK=
exit_if_var_does_not_exist BLANK
Output
$ bash tstempty.sh
Variable [VAR] is set to Test
Variable [BLANK] is unset. Exiting.
Improved Indirection Soup
After a bit of discussion in the comments and a suggestion, I think I have a version that works more consistently. Again, I qualify this with I am not sure it will work in all situations, but for the testing it seems to:
#!/bin/bash
function exit_if_var_does_not_exist {
local TMP_NAME=$1
local TMP_VALUE="${!TMP_NAME}"
if ! declare -p $1 >/dev/null 2>&1 ; then
[ -z "${!TMP_NAME}" ] && {
echo "Variable [${TMP_NAME}] is unset. Exiting."
return 1
}
elif [ "$TMP_VALUE" = "" ]; then
echo "Variable [${TMP_NAME}] is set to ''. Exiting."
return 1
fi
echo "Variable [${TMP_NAME}] is set to ${TMP_VALUE}"
}
VAR=Test
exit_if_var_does_not_exist VAR
# BLANK=
exit_if_var_does_not_exist BLANK
EMPTY=""
exit_if_var_does_not_exist EMPTY
Output
$ bash tstempty.sh
Variable [VAR] is set to Test
Variable [BLANK] is unset. Exiting.
Variable [EMPTY] is set to ''. Exiting.
Upvotes: 2