Что означает подстановка $ {! Var_name + x}?

10

Я нашел скрипт, который имеет функцию, которая проверяет, установлена ​​ли переменная, но я не очень хорошо ее понимаю.

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

Что именно происходит с этой заменой?

Карим Манауй
источник
связанные $ {! FOO} и zsh .
αғsнιη

Ответы:

17

В bashоболочке ${!var}есть переменная косвенность. Он расширяется до значения переменной, имя которой хранится в $var.

Расширение переменной ${var+value}- это расширение POSIX, которое расширяется, valueесли переменная varустановлена ​​(независимо от того, является ли ее значение пустым или нет).

Комбинируя их, ${!var+x}можно расширить, xесли переменная, имя которой хранится, $varустановлена.

Пример:

$ 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}}"

(пустая строка в качестве вывода)


Функция в вопросе может быть сокращена до

check_if_variable_is_set () { [ -n "${!1+x}" ]; }

или даже:

check_if_variable_is_set () { [ -v "$1" ]; }

или даже:

check_if_variable_is_set()[[ -v $1 ]]

Где -vэто bashиспытание на имя переменной , которая будет верно , если названная переменная установлена, и ложь в противном случае.


POSIXly, это может быть написано:

check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }

Обратите внимание, что все это потенциальные уязвимости при внедрении команд, если аргумент этой функции может оказаться под контролем злоумышленника. Попробуйте, например, с check_if_variable_is_set 'a[$(id>&2)]'.

Чтобы избежать этого, вы можете сначала проверить, что аргумент является допустимым именем переменной. Для переменных:

check_if_variable_is_set() {
  case $1 in
    ("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
    (*)  eval '[ -n "${'"$1"'+x}" ]'
  esac
}

(обратите внимание, что в вашей локали[[:alpha:]] будет проверяться наличие буквенных символов, в то время как некоторые оболочки принимают только буквенные символы из переносимого набора символов в их переменной)

Кусалананда
источник
На земле нет ничего более полного, чем это. Вы заслуживаете печенье для этого.
Карим Манауй
@KarimManaouil Треть этого печенья идет Стефану :-)
Кусалананда