10

I found a script that has a function that checks if a variable is set but i don't understand it very well.

check_if_variable_is_set() {
    var_name=$1
    if [ -z "${!var_name+x}" ]; then
        false
    else
        true
    fi
}

What exactly happens with this substitution ?

17

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)

  • There is nothing on earth more complete than this. You deserve a cookie for that. – Karim Manaouil Feb 18 at 16:47
  • @KarimManaouil A third of that cookie goes to Stéphane though :-) – Kusalananda Feb 18 at 17:35

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.