eval
und exec
beide sind in bash (1) Befehle eingebaut, die Befehle ausführen.
Ich sehe exec
auch ein paar Möglichkeiten, aber ist das der einzige Unterschied? Was passiert mit ihrem Kontext?
bash
shell
shell-builtin
Willian Paixao
quelle
quelle
Antworten:
eval
undexec
sind ganz andere Tiere. (Abgesehen von der Tatsache, dass beide Befehle ausführen, aber auch alles, was Sie in einer Shell tun.)Was
exec cmd
tut, ist genau dasselbe wie nur ausgeführtcmd
, außer dass die aktuelle Shell durch den Befehl ersetzt wird, anstatt dass ein separater Prozess ausgeführt wird. Intern sagen wir laufen/bin/ls
ruftfork()
ein Kind Prozess zu schaffen, und dannexec()
in das Kind auszuführen/bin/ls
.exec /bin/ls
auf der anderen Seite wird nicht gabeln, sondern nur die Schale ersetzt.Vergleichen Sie:
mit
echo $$
gibt die PID der Shell aus, die ich gestartet habe, und listet/proc/self
die PIDls
der Shell auf, die ausgeführt wurde. Normalerweise sind die Prozess-IDs unterschiedlich, jedoch mitexec
der Shell undls
der gleichen Prozess-ID. Außerdem wurde der folgende Befehlexec
nicht ausgeführt, da die Shell ersetzt wurde.Auf der anderen Seite:
eval
Führt die Argumente als Befehl in der aktuellen Shell aus. Mit anderen Worteneval foo bar
ist das gleiche wie nurfoo bar
. Variablen werden jedoch vor der Ausführung erweitert, sodass wir Befehle ausführen können, die in Shell-Variablen gespeichert sind:Es wird kein untergeordneter Prozess erstellt, daher wird die Variable in der aktuellen Shell festgelegt. (Natürlich
eval /bin/ls
wird ein untergeordneter Prozess erstellt, so wie es ein einfacher alter tun/bin/ls
würde.)Oder wir könnten einen Befehl haben, der Shell-Befehle ausgibt. Beim Ausführen wird
ssh-agent
der Agent im Hintergrund gestartet und es werden eine Reihe von Variablenzuweisungen ausgegeben, die in der aktuellen Shell festgelegt und von untergeordneten Prozessen verwendet werden können (diessh
Befehle, die Sie ausführen würden). Daherssh-agent
kann begonnen werden mit:Und die aktuelle Shell erhält die Variablen, die andere Befehle erben sollen.
Wenn die Variable
cmd
zufällig etwas wie enthältrm -rf $HOME
, ist das Ausführeneval "$cmd"
natürlich nicht das, was Sie tun möchten. Sogar Dinge wie Befehlsersetzungen innerhalb des Strings würden verarbeitet, daher sollte man wirklich sicher sein, dass die Eingabe ineval
sicher ist, bevor man sie verwendet.Oft ist es möglich, das
eval
versehentliche Verwechseln von Code und Daten zu vermeiden .quelle
eval
in erster Linie auch auf diese Antwort. Sachen wie indirekt Steuern von Variablen können in vielen Schalen durch getan werdendeclare
/typeset
/nameref
wie und Erweiterungen${!var}
, also würde ich diejenigen statt verwenden ,eval
es sei denn ich hatte wirklich , es zu vermeiden.exec
erstellt keinen neuen Prozess. Es ersetzt den aktuellen Prozess durch den neuen Befehl. Wenn Sie dies über die Befehlszeile getan haben, wird Ihre Shell-Sitzung effektiv beendet (und Sie werden möglicherweise abgemeldet oder das Terminalfenster geschlossen!).z.B
Hier bin ich in
ksh
(meine normale Muschel). Ich fange anbash
und dann drin schlag ichexec /bin/echo
. Wir können sehen, dass ich später wieder hineingefallen bin,ksh
weil derbash
Prozess durch ersetzt wurde/bin/echo
.quelle
TL; DR
exec
wird verwendet, um den aktuellen Shell-Prozess durch neue zu ersetzen und Stream-Umleitungs- / Dateideskriptoren zu behandeln, wenn kein Befehl angegeben wurde.eval
wird verwendet, um Zeichenfolgen als Befehle auszuwerten. Beide können verwendet werden, um einen Befehl mit zur Laufzeit bekannten Argumenten zu erstellen und auszuführen,exec
ersetzen jedoch zusätzlich zur Ausführung von Befehlen den Prozess der aktuellen Shell.Exec Buil-In
Syntax:
Laut Handbuch, wenn dort ein Befehl angegeben ist, ist dieser eingebaut
Mit anderen Worten, wenn Sie
bash
mit PID 1234 ausgeführt wurden undexec top -u root
in dieser Shell ausgeführt werden sollten, hat dertop
Befehl PID 1234 und ersetzt Ihren Shell-Prozess.Wo ist das nützlich? In so genannten Wrapper-Skripten. Solche Skripte bauen eine Reihe von Argumenten auf oder treffen bestimmte Entscheidungen darüber, welche Variablen an die Umgebung übergeben werden sollen, und
exec
ersetzen sich dann durch den angegebenen Befehl. Dabei werden natürlich dieselben Argumente bereitgestellt, die das Wrapper-Skript auf diesem Weg aufgebaut hat.Im Handbuch heißt es außerdem:
Dies ermöglicht es uns, alles von aktuellen Shells-Ausgabestreams in eine Datei umzuleiten. Dies kann für Protokollierungs- oder Filterzwecke nützlich sein, bei denen Sie nicht
stdout
nur Befehle sehen möchtenstderr
. Zum Beispiel so:Dieses Verhalten macht es praktisch, wenn Sie sich in Shell-Skripten anmelden, Streams umleiten, um Dateien oder Prozesse zu trennen , und andere unterhaltsame Dinge mit Dateideskriptoren.
Auf der Quellcode-Ebene ist mindestens für
bash
Version 4.3 dasexec
eingebaute in definiertbuiltins/exec.def
. Es analysiert die empfangenen Befehle und leitet, falls vorhanden, Dinge anshell_execve()
die in derexecute_cmd.c
Datei definierte Funktion weiter .Um es kurz zu machen, es gibt eine Familie von
exec
Befehlen in der Programmiersprache C, dieshell_execve()
im Grunde genommen eine Wrapper-Funktion vonexecve
:eval eingebaut
Das Handbuch zu Bash 4.3 besagt (Hervorhebung von mir hinzugefügt):
Beachten Sie, dass kein Prozessaustausch stattfindet. Anders als
exec
bei der Simulation vonexecve()
Funktioneneval
dient die integrierte Funktion nur zum "Auswerten" von Argumenten, als hätte der Benutzer sie in die Befehlszeile eingegeben. Dadurch entstehen neue Prozesse.Wo könnte das nützlich sein? In dieser Antwort wies Gilles darauf hin , dass "... eval nicht sehr oft verwendet wird. In einigen Shells wird am häufigsten der Wert einer Variablen abgerufen, deren Name erst zur Laufzeit bekannt ist". Persönlich habe ich es in einigen Skripten unter Ubuntu verwendet, in denen es notwendig war, einen Befehl basierend auf dem spezifischen Arbeitsbereich auszuführen / auszuwerten, den der Benutzer aktuell verwendete.
Auf der Quellcode-Ebene wird sie in definiert
builtins/eval.def
und übergibt die analysierte Eingabezeichenfolge anevalstring()
function.eval
Kann unter anderem Variablen zuweisen, die in der aktuellen Shell-Ausführungsumgebung verbleiben, währendexec
Folgendes nicht möglich ist:quelle
UH, was? Der springende Punkt dabei
eval
ist, dass dadurch in keiner Weise ein untergeordneter Prozess erstellt wird. Wenn ich macheIn einer Shell hat danach die aktuelle Shell das Verzeichnis geändert. Weder wird
exec
ein neuer untergeordneter Prozess erstellt, noch wird die aktuelle ausführbare Datei (dh die Shell) für den angegebenen Prozess geändert. Die Prozess-ID (und geöffnete Dateien und andere Informationen) bleiben unverändert. Im Gegensatz dazu kehrteval
einexec
nicht zur aufrufenden Shell zurück, es sei denn, die Shellexec
selbst schlägt fehl, weil sie die ausführbare Datei nicht finden oder laden kann oder weil es zu Problemen bei der Argumenterweiterung kommt.eval
Grundsätzlich interpretiert es seine Argumente nach der Verkettung als Zeichenfolge, dh es wird eine zusätzliche Ebene für die Platzhaltererweiterung und die Argumentaufteilung erstellt.exec
macht so etwas nicht.quelle
Auswertung
Diese Arbeiten:
Diese tun jedoch nicht:
Prozessabbild ersetzen
Dieses Beispiel zeigt, wie
exec
das Image des aufrufenden Prozesses ersetzt wird:Beachten Sie, dass
exec echo $$
mit der PID der Unterschale lief! Darüber hinaus waren wir nach Fertigstellung wieder in unserer ursprünglichensh$
Hülle.Auf der anderen Seite,
eval
ist nicht ersetzt das Prozessabbild. Stattdessen wird der angegebene Befehl so ausgeführt, wie Sie es normalerweise in der Shell selbst tun würden. (Natürlich, wenn Sie einen Befehl ausführen, für den ein Prozess erzeugt werden muss ... genau das tut er!)quelle
exec
)