Ich habe ein Bash-Skript gelesen, das jemand erstellt hat, und ich habe festgestellt, dass der Autor eval nicht verwendet, um eine Variable als Befehl auszuwerten.
Der Autor verwendete
bash -c "$1"
Anstatt von
eval "$1"
Ich gehe davon aus, dass eval die bevorzugte Methode ist und wahrscheinlich sowieso schneller. Ist das wahr?
Gibt es einen praktischen Unterschied zwischen den beiden? Was sind bemerkenswerte Unterschiede zwischen den beiden?
bash
shell-script
bash-script
Wer bin ich
quelle
quelle
e='echo foo'; $e
funktioniert gutAntworten:
eval "$1"
Führt den Befehl im aktuellen Skript aus. Es kann Shell-Variablen aus dem aktuellen Skript festlegen und verwenden, Umgebungsvariablen für das aktuelle Skript festlegen, Funktionen aus dem aktuellen Skript festlegen und verwenden, das aktuelle Verzeichnis, die Umask, die Grenzwerte und andere Attribute für das aktuelle Skript festlegen usw.bash -c "$1"
Führt den Befehl in einem vollständig separaten Skript aus, das Umgebungsvariablen, Dateideskriptoren und andere Prozessumgebungen erbt (aber keine Änderungen zurückgibt), jedoch keine internen Shell-Einstellungen (Shell-Variablen, Funktionen, Optionen, Traps usw.) erbt.Es gibt einen anderen Weg,
(eval "$1")
der den Befehl in einer Subshell ausführt: Er erbt alles vom aufrufenden Skript, überträgt aber keine Änderungen zurück.Angenommen, die Variable
dir
wird nicht exportiert und$1
lautetcd "$foo"; ls
dann:cd /starting/directory; foo=/somewhere/else; eval "$1"; pwd
listet den Inhalt von/somewhere/else
und druckt/somewhere/else
.cd /starting/directory; foo=/somewhere/else; (eval "$1"); pwd
listet den Inhalt von/somewhere/else
und druckt/starting/directory
.cd /starting/directory; foo=/somewhere/else; bash -c "$1"; pwd
Listet den Inhalt von auf/starting/directory
(dacd ""
das aktuelle Verzeichnis nicht geändert wird) und druckt/starting/directory
.quelle
(eval "$1")
hat nichts damit zu tunsource
. Es ist nur eine Kombination von(…)
undeval
.source foo
entspricht in etwaeval "$(cat foo)"
.eval
und.dot
ist , dass dieeval
Arbeiten mit Argumenten und.dot
arbeitet mit Dateien.Der wichtigste Unterschied zwischen
Und
Ist das erstere läuft in einer Unterschale und das letztere nicht. Damit:
AUSGABE:
AUSGABE:
Ich habe jedoch keine Ahnung, warum jemand die ausführbare Datei jemals
bash
auf diese Weise verwenden würde. Wenn Sie es aufrufen müssen, verwenden Sie die POSIX-Garantiesh
. Oder(subshell eval)
wenn Sie Ihre Umwelt schützen möchten.Ich persönlich bevorzuge
.dot
vor allem die Muschel .AUSGABE
ABER BRAUCHEN SIE ES?
Die einzige Ursache für die Verwendung besteht in dem Fall, dass Ihre Variable tatsächlich eine andere Variable zuweist oder auswertet, oder dass die Wortteilung für die Ausgabe wichtig ist.
Zum Beispiel:
AUSGABE:
Das funktioniert, aber nur, weil
echo
die Anzahl der Argumente keine Rolle spielt.AUSGABE:
Sehen? Die doppelten Anführungszeichen kommen daher, dass das Ergebnis der Erweiterung der Shell
$var
nicht ausgewertet wirdquote-removal
.AUSGABE:
Aber mit
eval
odersh
:AUSGABE:
Wenn wir
eval
odersh
die Shell verwenden, werden die Ergebnisse der Erweiterungen in einem zweiten Durchgang überprüft und auch als potenzieller Befehl ausgewertet, sodass die Anführungszeichen einen Unterschied ausmachen. Sie können auch tun:AUSGABE
quelle
Ich habe einen kurzen Test gemacht:
(Ja, ich weiß, ich habe bash -c verwendet, um die Schleife auszuführen, aber das sollte keinen Unterschied machen).
Die Ergebnisse:
Ist
eval
also schneller. Aus der Manpage voneval
:bash -c
Führt den Befehl natürlich in einer Bash-Shell aus. Ein Hinweis: Ich habe verwendet,/bin/echo
weilecho
eine Shell mit eingebaut istbash
, was bedeutet, dass kein neuer Prozess gestartet werden muss. Das Ersetzen/bin/echo
durchecho
für denbash -c
Test dauerte1.28s
. Das ist ungefähr das Gleiche. Isteval
jedoch schneller für die Ausführung von ausführbaren Dateien. Der Hauptunterschied besteht darin, dasseval
keine neue Shell gestartet wird (der Befehl wird in der aktuellenbash -c
Shell ausgeführt ), wohingegen eine neue Shell gestartet und dann der Befehl in der neuen Shell ausgeführt wird. Das Starten einer neuen Shell braucht Zeit und ist deshalbbash -c
langsamer alseval
.quelle
bash -c
miteval
nichtexec
.bash -c
ist nicht so schlimm ...