Was bedeutet die Substitution $ {! Var_name + x}?

10

Ich habe ein Skript gefunden, das eine Funktion hat, die prüft, ob eine Variable gesetzt ist, aber ich verstehe es nicht sehr gut.

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

Was genau passiert mit dieser Substitution?

Karim Manaouil
quelle
verwandte $ {! FOO} und zsh .
αғsнιη

Antworten:

17

In der bashShell ${!var}befindet sich eine variable Indirektion. Es wird auf den Wert der Variablen erweitert, deren Name beibehalten wird $var.

Die Variablenerweiterung ${var+value}ist eine POSIX-Erweiterung , die erweitert wird, valuewenn die Variable festgelegt varist (unabhängig davon, ob ihr Wert leer ist oder nicht).

Wenn Sie diese kombinieren, wird ${!var+x}dies erweitert, xwenn die Variable festgelegt wird, in der der Name beibehalten $varwird.

Beispiel:

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

(leere Zeile als Ausgabe)


Die Funktion in der Frage könnte auf verkürzt werden

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

oder auch:

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

oder auch:

check_if_variable_is_set()[[ -v $1 ]]

Wo -vist ein bashTest für einen Variablennamen, der wahr ist, wenn die benannte Variable gesetzt ist, und andernfalls falsch.


POSIXly könnte geschrieben werden:

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

Beachten Sie, dass all dies potenzielle Sicherheitsanfälligkeiten hinsichtlich der Befehlsinjektion sind, wenn das Argument für diese Funktion möglicherweise von einem Angreifer kontrolliert wird. Versuchen Sie es zum Beispiel mit check_if_variable_is_set 'a[$(id>&2)]'.

Um dies zu verhindern, sollten Sie zunächst überprüfen, ob das Argument ein gültiger Variablenname ist. Für Variablen:

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

(Beachten Sie, dass in Ihrem Gebietsschema[[:alpha:]] nach alphabetischen Zeichen gesucht wird, während einige Shells nur alphabetische Zeichen aus dem tragbaren Zeichensatz in ihrer Variablen akzeptieren.)

Kusalananda
quelle
Nichts auf der Erde ist vollständiger als dies. Sie verdienen einen Keks dafür.
Karim Manaouil
@ KarimManaouil Ein Drittel dieses Cookies geht jedoch an Stéphane :-)
Kusalananda