eval
nimmt eine Zeichenfolge als Argument und wertet sie aus, als ob Sie diese Zeichenfolge in eine Befehlszeile eingegeben hätten. (Wenn Sie mehrere Argumente übergeben, werden diese zunächst mit Leerzeichen verbunden.)
${$n}
ist ein Syntaxfehler in bash. Innerhalb der geschweiften Klammern können Sie nur einen Variablennamen mit einigen möglichen Präfixen und Suffixen haben, aber Sie können keine willkürliche Bash-Syntax haben und insbesondere können Sie keine Variablenerweiterung verwenden. Es gibt jedoch eine Art zu sagen „der Wert der Variablen, deren Name in dieser Variablen steht“:
echo ${!n}
one
$(…)
führt den in Klammern angegebenen Befehl in einer Subshell aus (d. h. in einem separaten Prozess, der alle Einstellungen wie Variablenwerte von der aktuellen Shell erbt) und sammelt seine Ausgabe. Also echo $($n)
läuft $n
als Shell-Befehl und zeigt seine Ausgabe an. Seit $n
ergibt 1
, $($n)
versucht, den Befehl 1
auszuführen , die nicht existiert.
eval echo \${$n}
führt die an eval
übergebenen Parameter aus . Nach der Erweiterung sind die Parameter echo
und ${1}
. Also eval echo \${$n}
führt den Befehl echo ${1}
aus .
Beachten Sie, dass Sie die meiste Zeit doppelte Anführungszeichen um Variablenersetzungen und Befehlsersetzungen verwenden müssen (d. h. immer wenn ein $
steht ):"$foo", "$(foo)"
. Setzen Sie Variablen- und Befehlsersetzungen immer in doppelte Anführungszeichen , es sei denn, Sie wissen, dass Sie sie weglassen müssen. Ohne die doppelten Anführungszeichen führt die Shell eine Feldaufteilung durch (d. h. sie teilt den Wert der Variablen oder die Ausgabe des Befehls in separate Wörter auf) und behandelt dann jedes Wort als Platzhaltermuster. Zum Beispiel:
$ ls
file1 file2 otherfile
$ set -- 'f* *'
$ echo "$1"
f* *
$ echo $1
file1 file2 file1 file2 otherfile
$ n=1
$ eval echo \${$n}
file1 file2 file1 file2 otherfile
$eval echo \"\${$n}\"
f* *
$ echo "${!n}"
f* *
eval
wird nicht sehr oft verwendet. In einigen Shells besteht die häufigste Verwendung darin, den Wert einer Variablen zu erhalten, deren Name bis zur Laufzeit nicht bekannt ist. In der Bash ist dies dank ${!VAR}
nicht notwendig Syntax. eval
ist immer noch nützlich, wenn Sie einen längeren Befehl erstellen müssen, der Operatoren, reservierte Wörter usw. enthält.
Stellen Sie sich eval einfach so vor, dass Sie „Ihren Ausdruck vor der Ausführung ein weiteres Mal auswerten“
eval echo \${$n}
wird zu echo $1
nach der ersten Bewertungsrunde. Drei Änderungen zu beachten:
- Die
\$
wurde zu$
(Der umgekehrte Schrägstrich wird benötigt, ansonsten wird versucht,${$n}
auszuwerten , was eine Variable namens{$n}
bedeutet , was nicht erlaubt ist) $n
wurde zu1
ausgewertet- Der
eval
verschwunden
In der zweiten Runde ist es im Grunde echo $1
die direkt ausgeführt werden können.
Also eval <some command>
wertet zuerst <some command>
aus (mit auswerten meine ich hier Variablen ersetzen, maskierte Zeichen durch die richtigen ersetzen usw.) und dann den resultierenden Ausdruck noch einmal ausführen.
eval
wird verwendet, wenn Sie Variablen dynamisch erstellen oder Ausgaben von Programmen lesen möchten, die speziell dafür entwickelt wurden, so gelesen zu werden. Beispiele finden Sie unter http://mywiki.wooledge.org/BashFAQ/048. Der Link enthält auch einige typische Möglichkeiten, wie eval
verwendet wird, und die damit verbundenen Risiken.
Meiner Erfahrung nach besteht eine "typische" Verwendung von eval darin, Befehle auszuführen, die Shell-Befehle zum Setzen von Umgebungsvariablen generieren.
Vielleicht haben Sie ein System, das eine Sammlung von Umgebungsvariablen verwendet, und Sie haben ein Skript oder Programm, das festlegt, welche gesetzt werden sollen und welche Werte sie haben. Jedes Mal, wenn Sie ein Skript oder Programm ausführen, wird es in einem gegabelten Prozess ausgeführt, sodass alles, was es direkt mit Umgebungsvariablen macht, beim Beenden verloren geht. Aber dieses Skript oder Programm kann die Exportbefehle an stdout senden.
Ohne eval müssten Sie stdout in eine temporäre Datei umleiten, die temporäre Datei beziehen und sie dann löschen. Mit eval können Sie einfach:
eval "$(script-or-program)"
Beachten Sie, dass die Anführungszeichen wichtig sind. Nehmen Sie dieses (erfundene) Beispiel:
# activate.sh
echo 'I got activated!'
# test.py
print("export foo=bar/baz/womp")
print(". activate.sh")
$ eval $(python test.py)
bash: export: `.': not a valid identifier
bash: export: `activate.sh': not a valid identifier
$ eval "$(python test.py)"
I got activated!