In the bash
shell, ${!var}
is a variable indirection. It expands to the value of the variable whose name is kept in $var
.
The variable expansion ${var+value}
is a POSIX expansion that expands to value
if the variable var
is set (no matter if its value is empty or not).
Combining these, ${!var+x}
would expand to x
if the variable whose name is kept in $var
is set.
Example:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(empty line as output)
The function in the question could be shortened to
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
or even:
check_if_variable_is_set () { [ -v "$1" ]; }
or even:
check_if_variable_is_set()[[ -v $1 ]]
Where -v
is a bash
test on a variable name which will be true if the named variable is set, and false otherwise.
POSIXly, it could be written:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Note that all those are potential command injection vulnerabilities if the argument to that function could end up being under control of an attacker. Try for instance with check_if_variable_is_set 'a[$(id>&2)]'
.
To guard against that, you may want to verify that the argument is a valid variable name first. For variables:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(note that [[:alpha:]]
will check for alphabetical characters in your locale while some shells only accept alphabetical characters from the portable character set in their variable)