Ich möchte Variablen mit dynamisch Werte zuweisen eval
. Das folgende Dummy-Beispiel funktioniert:
var_name="fruit"
var_value="orange"
eval $(echo $var_name=$var_value)
echo $fruit
orange
Wenn der Variablenwert jedoch Leerzeichen enthält, wird eval
ein Fehler zurückgegeben, auch wenn $var_value
zwischen Anführungszeichen gesetzt wird:
var_name="fruit"
var_value="blue orange"
eval $(echo $var_name="$var_value")
bash: orange : command not found
Wie kann man das umgehen?
eval
diese Weise ist falsch. Sie erweitern,$var_value
bevor Sie es übergeben,eval
was bedeutet, dass es als Shell-Code interpretiert wird! (versuchen Sie es zum Beispiel mitvar_value="';:(){ :|:&};:'"
)eval
(was ein Grund ist, warum ich sagte, dass Sie nicht verwenden sollteneval
).$var_value
ist jedoch die Umkehrung der Anführungszeichen - wenn Sie einen sicheren Wert für annehmen$var_name
(was wirklich eine ebenso gefährliche Annahme sein kann) , sollten Sie die doppelten Anführungszeichen der rechten Seite in einfache Anführungszeichen einschließen - nicht und umgekehrt.eval
, usingprintf
und seinbash
-spezifisches%q
Format behoben . Dies ist immer noch keine Empfehlungeval
, aber ich denke, es ist sicherer als zuvor. Die Tatsache, dass Sie sich so viel Mühe geben müssen, um es zum Laufen zu bringen, ist ein Beweis dafür, dass Siedeclare
stattdessen Referenzen verwenden oder benennen sollten .set -- a bunch of args; eval "process2 $(process1 "$@")"
woprocess1
nur zitierte Zahlen wie gedruckt werden"${1}" "${8}" "${138}"
. Das ist verrückt einfach - und so einfach wie'"${'$((i=$i+1))'}" '
in den meisten Fällen. Indizierte Referenzen machen es sicher, robust und schnell . Trotzdem - ich habe aufgestimmt.Ein guter Weg, um damit zu arbeiten,
eval
besteht darin, esecho
zu Testzwecken zu ersetzen .echo
undeval
arbeiten genauso (wenn wir die\x
Erweiterung durch einigeecho
Implementierungen wiebash
's unter bestimmten Bedingungen aufheben).Beide Befehle verbinden ihre Argumente mit einem Leerzeichen dazwischen. Der Unterschied besteht darin, dass das Ergebnis
echo
angezeigt wird, während das Ergebnis als Shell-Codeeval
ausgewertet / interpretiert wird .Also, um zu sehen, welcher Shell-Code
würde bewerten, können Sie ausführen:
Das ist nicht was du willst, was du willst ist:
Auch
$(echo ...)
hier macht es keinen Sinn.Um das Obige auszugeben, würden Sie Folgendes ausführen:
Um es zu interpretieren, ist das einfach:
Beachten Sie, dass damit auch einzelne Array-Elemente festgelegt werden können:
Wie andere bereits gesagt haben, können Sie Folgendes verwenden, wenn es Ihnen egal ist, ob Ihr Code
bash
spezifisch istdeclare
:Beachten Sie jedoch, dass es einige Nebenwirkungen hat.
Der Gültigkeitsbereich der Variablen ist auf die Funktion beschränkt, in der sie ausgeführt wird. Sie können sie also beispielsweise nicht in folgenden Situationen verwenden:
Denn das würde deklarieren, dass eine
foo
Variable local tosetvar
so nutzlos wäre.bash-4.2
hinzugefügt , um eine-g
Option fürdeclare
ein erklären , global , variabel , aber das ist nicht das, was wir entweder als unser wollensetvar
einen würde gesetzt globalen var im Gegensatz zu dem dem Anrufer , wenn der Anrufer eine Funktion ist, wie in:was ausgeben würde:
Beachten Sie außerdem, dass while
declare
aufgerufen wirddeclare
(bash
das Konzept wurde tatsächlich aus demtypeset
Buildin der Korn-Shell entlehnt), wenn die Variable bereits festgelegt ist,declare
keine neue Variable deklariert und die Art der Zuweisung vom Typ der Variablen abhängt.Zum Beispiel:
wird ein anderes Ergebnis erzeugen (und möglicherweise böse Nebenwirkungen haben), wenn
varname
es zuvor als Skalar , Array oder assoziatives Array deklariert wurde .quelle
bash
nicht verfügbar ist (oder wenn Sie feststellen, dass Sie eine bessere / schnellere Shell benötigen). Dieeval
Syntax funktioniert in allen Bourne-ähnlichen Shells und ist POSIX, sodass auf allen Systemen einesh
solche vorhanden ist. (Das bedeutet auch, dass meine Antwort auf alle Muscheln zutrifft. Wie hier häufig vorkommt, wird früher oder später eine nicht bashspezifische Frage als Duplikat dieser Frage geschlossen.$var_name
Token enthält? ... wie;
?eval
unddeclare
(denken Sie anPATH
,TMOUT
,PS4
,SECONDS
...).export
. Ich folge jedoch nicht den Klammern am Ende.Wenn Sie tun:
... und
$name
enthält ein;
- oder eines von mehreren anderen Tokens, die die Shell möglicherweise als Begrenzung eines einfachen Befehls interpretiert -, dem eine korrekte Shell-Syntax vorausgeht, die ausgeführt wird.AUSGABE
Es kann jedoch manchmal möglich sein, die Auswertung und Ausführung solcher Anweisungen zu trennen. Zum Beispiel
alias
kann ein Befehl vorab ausgewertet werden. Im folgenden Beispiel wird die Variablendefinition in einer gespeichertalias
, die nur dann erfolgreich deklariert werden kann, wenn die$nm
auszuwertende Variable keine Bytes enthält, die nicht mit ASCII-alphanumerischen Zeichen oder übereinstimmen_
.eval
wird hier verwendet, um das Neuealias
von einem Variablennamen aufzurufen. Es wird jedoch nur dann aufgerufen, wenn die vorherigealias
Definition erfolgreich ist, und obwohl ich weiß, dass viele verschiedene Implementierungen viele verschiedene Arten von Werten füralias
Namen akzeptieren , bin ich noch nicht auf einen gestoßen, der einen vollständig leeren Wert akzeptiert .Die Definition in der
alias
ist jedoch für_$nm
, und dies soll sicherstellen, dass keine signifikanten Umgebungswerte überschrieben werden. Ich kenne keine nennenswerten Umgebungswerte, die mit a beginnen,_
und es ist normalerweise eine sichere Wette für die halbprivate Deklaration.Wenn die
alias
Definition erfolgreich ist, deklariert sie jedenfalls den Wert einesalias
Namens für$nm
. Undeval
ruft das nur auf,alias
wenn auch nicht mit einer Zahl beginnt - sonsteval
bekommt man nur ein Nullargument. Wenn also beide Bedingungen erfüllt sindeval
, wird der Alias aufgerufen und die im Alias gespeicherte Variablendefinition erstellt. Danach wird der neuealias
Wert sofort aus der Hash-Tabelle entfernt.quelle
;
ist in Variablennamen nicht erlaubt. Wenn Sie nicht die Kontrolle über den Inhalt von haben$name
, müssen Sie ihn auch fürexport
/ bereinigendeclare
. Währendexport
Code nicht ausgeführt wird, setzen einige Variablen wiePATH
,PS4
und viele davoninfo -f bash -n 'Bash Variables'
haben gleichermaßen gefährliche Nebenwirkungen.eval
ersten Durchgang - es ist eine variable Erweiterung. Wie Sie an anderer Stelle sagten, ist dies in diesem Zusammenhang sehr erlaubt. Trotzdem ist das $ PATH-Argument sehr gut - ich habe eine kleine Änderung vorgenommen und werde später einige hinzufügen.zsh
,pdksh
,mksh
,yash
beschweren sich nicht aufunset 'a;b'
.unset -v -- ...
.