W bashpowłoce ${!var}jest zmienna pośrednia. Rozwija się do wartości zmiennej, której nazwa jest przechowywana $var.
Rozszerzenie zmiennej ${var+value}jest rozszerzeniem POSIX, które rozwija się, valuejeśli zmienna varjest ustawiona (bez względu na to, czy jej wartość jest pusta, czy nie).
Łącząc je, ${!var+x}rozwinie się do, xjeśli ustawiona jest zmienna, której nazwa jest przechowywana $var.
Przykład:
$ 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}}"
(pusty wiersz jako wynik)
Funkcja w pytaniu może zostać skrócona
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
lub nawet:
check_if_variable_is_set () { [ -v "$1" ]; }
lub nawet:
check_if_variable_is_set()[[ -v $1 ]]
Gdzie -vjest bashtest na nazwę zmiennej, która będzie prawdziwa, jeśli zmienna nazwana jest ustawiona, a false w przeciwnym razie.
POSIXly może być napisany:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Zauważ, że wszystkie te są potencjalne podatności na wstrzykiwanie poleceń, jeśli argumentem tej funkcji może być kontrola nad atakującym. Spróbuj na przykład z check_if_variable_is_set 'a[$(id>&2)]'.
Aby temu zapobiec, możesz najpierw sprawdzić, czy argument jest poprawną nazwą zmiennej. Dla zmiennych:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(zwróć uwagę, że [[:alpha:]]sprawdzi znaki alfabetu w twoim języku, podczas gdy niektóre powłoki akceptują tylko znaki alfabetu z przenośnego zestawu znaków w swojej zmiennej)