Wozu dient der Befehl exec in Shell-Skripten?

249

Kann jemand anhand einfacher Beispiele erklären, wozu der Befehl exec in Shell-Skripten verwendet wird?

user2400564
quelle
31
Die Links zu linux.about.com sind nicht hilfreich. Sie machen nicht aus der Ferne klar, wie sich die Ausführung eines Befehls oder einer Befehlspipeline mit 'exec' von der normalen Ausführung unterscheidet. Daher die Frage des OP "Was nützt exec?"
Jonathan Hartley
2
Stack Overflow ist eine Site für Programmier- und Entwicklungsfragen. Diese Frage scheint nicht zum Thema zu gehören, da es nicht um Programmierung oder Entwicklung geht. Weitere Informationen zu den Themen finden Sie hier in der Hilfe. Vielleicht ist Super User oder Unix & Linux Stack Exchange ein besserer Ort, um zu fragen.
JWW

Antworten:

281

Die execeingebauten Befehlsspiegelfunktionen im Kernel, auf execvederen Basis eine Familie basiert , die üblicherweise von C aufgerufen wird.

execErsetzt das aktuelle Programm im aktuellen Prozess, ohne forkeinen neuen Prozess zu erstellen. Es ist nicht etwas, das Sie in jedem Skript verwenden würden, das Sie schreiben, aber es ist gelegentlich nützlich. Hier sind einige Szenarien, die ich verwendet habe;

  1. Wir möchten, dass der Benutzer ein bestimmtes Anwendungsprogramm ohne Zugriff auf die Shell ausführt. Wir könnten das Anmeldeprogramm in / etc / passwd ändern, aber vielleicht möchten wir, dass die Umgebungseinstellung aus Startdateien verwendet wird. In (sagen wir) .profilesagt die letzte Aussage so etwas wie:

     exec appln-program

    Jetzt gibt es keine Shell mehr, zu der man zurückkehren kann. Selbst wenn es appln-programabstürzt, kann der Endbenutzer nicht zu einer Shell gelangen, da diese nicht vorhanden ist - execsie hat sie ersetzt.

  2. Wir möchten eine andere Shell als die in / etc / passwd verwenden. So dumm es auch scheinen mag, auf einigen Websites können Benutzer ihre Anmeldeshell nicht ändern. Bei einer Site, die ich kenne, haben alle angefangen csh, und alle haben einfach .logineinen Aufruf an ihre (csh-Startdatei) gesendet ksh. Während das funktionierte, lief ein streunender cshProzess und die Abmeldung war zweistufig, was verwirrend werden konnte. Also haben wir es geändert exec ksh, indem wir gerade das C-Shell-Programm durch die Korn-Shell ersetzt und alles einfacher gemacht haben (es gibt andere Probleme damit, wie die Tatsache, dass kshes sich nicht um eine Login-Shell handelt).

  3. Nur um Prozesse zu speichern. Wenn wir anrufen prog1 -> prog2 -> prog3 -> prog4usw. und niemals zurückkehren, machen Sie jeden Anruf zu einem Exec. Es spart Ressourcen (zugegebenermaßen nicht viel, sofern es nicht wiederholt wird) und vereinfacht das Herunterfahren.

Sie haben offensichtlich execirgendwo verwendet gesehen , vielleicht könnten wir seine Verwendung rechtfertigen, wenn Sie den Code zeigen, der Sie nervt.

Bearbeiten : Ich habe festgestellt, dass meine Antwort oben unvollständig ist. Es gibt zwei Verwendungen von execin Shells wie kshund bash- zum Öffnen von Dateideskriptoren. Hier sind einige Beispiele:

exec 3< thisfile          # open "thisfile" for reading on file descriptor 3
exec 4> thatfile          # open "thatfile" for writing on file descriptor 4
exec 8<> tother           # open "tother" for reading and writing on fd 8
exec 6>> other            # open "other" for appending on file descriptor 6
exec 5<&0                 # copy read file descriptor 0 onto file descriptor 5
exec 7>&4                 # copy write file descriptor 4 onto 7
exec 3<&-                 # close the read file descriptor 3
exec 6>&-                 # close the write file descriptor 6

Beachten Sie, dass der Abstand hier sehr wichtig ist. Wenn Sie zwischen der fd-Nummer und dem Umleitungssymbol ein Leerzeichen einfügen exec, wird die ursprüngliche Bedeutung wiederhergestellt:

  exec 3 < thisfile       # oops, overwrite the current program with command "3"

Es gibt mehrere Möglichkeiten , wie Sie diese, auf KSH Gebrauch verwenden können , read -uoder print -u, auf bash, zum Beispiel:

read <&3
echo stuff >&4
cdarke
quelle
22
Es gibt auch eine andere Verwendung, die ich als sehr praktisch und erwähnenswert empfunden habe, da sie sich auf Python-Webanwendungen bezieht und etwas zwischen Ihren (fantastischen) Antworten 2 und 3 zu liegen scheint. Normalerweise führe ich wsgi-Webanwendungen (z. B. Django oder Flasche) über einen Supervisor aus , der ein Gunicorn anruft App: Letzteres erfordert bekanntermaßen einige Umgebungsvariablen. Es ist viel einfacher und wartbarer, Gunicorn über ein Shell-Skript auszuführen, das alles einrichtet und exec gunicorndem Supervisor schließlich die richtige PID zurückgibt.
gru
1
Die Dokumente sagen, dass execdies für die Umleitung verwendet werden kann:> Wenn kein Befehl angegeben ist, werden alle Umleitungen in der aktuellen Shell wirksam und der Rückgabestatus ist 0. Wenn ein Umleitungsfehler vorliegt, ist der Rückgabestatus 1. Aber wie geht das ? exectatsächlich arbeiten, um einen Dateideskriptor zu ändern? Warum wird dieser spezielle Befehl für diese Aufgabe ausgewählt? (Markdown schlägt gerade fehl?)
Ray
@ Ray: Das Beste, was ich tun kann: pubs.opengroup.org/onlinepubs/009604599/utilities/exec.html . Wenn Sie wissen müssen, wie es geht, schauen Sie sich den Shell-Quellcode an.
Cdarke
7
Eine andere Verwendung: Leiten Sie alle Ausgaben eines Skripts in eine Protokolldatei umexec >.\logfilename.log 2>&1
Hogan
1
@Carmageddon: &>ist eine bashErweiterung (siehe man bash) und Ihr Beispiel entspricht exec >/var/log/userdata.log 2>&1. Mit anderen Worten, es leitet stdout und stderr in diese Datei um. Die folgenden Befehle erben diese Umleitungen, sofern sie nicht zurückgesetzt werden. Sie werden jedoch ausgeführt.
Cdarke
41

Nur um die akzeptierte Antwort mit einer kurzen, für Neulinge geeigneten kurzen Antwort zu ergänzen, brauchen Sie sie wahrscheinlich nicht exec.

Wenn Sie noch hier sind, sollte die folgende Diskussion hoffentlich zeigen, warum. Wenn Sie rennen, sagen Sie,

sh -c 'command'

Sie führen eine shInstanz aus und beginnen dann commandals untergeordnetes Element dieser shInstanz. Wenn der commandVorgang abgeschlossen ist, wird auch die shInstanz beendet.

sh -c 'exec command'

führt eine shInstanz aus, ersetzt diese shInstanz dann durch die commandBinärdatei und führt diese stattdessen aus.

Natürlich sind beide in diesem begrenzten Kontext nutzlos; du willst einfach

command

Es gibt einige Randbedingungen, in denen die Shell ihre Konfigurationsdatei lesen oder die Umgebung auf andere Weise als Vorbereitung für die Ausführung einrichten soll command. Dies ist so ziemlich die einzige Situation, in der exec commandes nützlich ist.

#!/bin/sh
ENVIRONMENT=$(some complex task)
exec command

Dies führt einige Dinge aus, um die Umgebung so vorzubereiten, dass sie das enthält, was benötigt wird. Sobald dies erledigt ist, ist die shInstanz nicht mehr erforderlich. Daher ist es eine (geringfügige) Optimierung, die shInstanz einfach durch den commandProzess zu ersetzen , anstatt shsie als untergeordneten Prozess auszuführen und darauf zu warten. Beenden Sie sie dann, sobald sie abgeschlossen ist.

Wenn Sie am Ende eines Shell-Skripts so viele Ressourcen wie möglich für einen umfangreichen Befehl freigeben möchten, möchten Sie execdiesen Befehl möglicherweise als Optimierung verwenden.

Wenn etwas zwingt SieFormal laufen , shaber sie wirklich laufen etwas anderes wollen, exec something elseist natürlich das Problem zu umgehen , die unerwünschte zu ersetzen shInstanz (wie zum Beispiel , wenn Sie wirklich Ihre eigene spiffy laufen wollen goshstatt , shaber bei Sie sind , die nicht in /etc/shellsso können Sie Geben Sie es nicht als Ihre Login-Shell an.

Die zweite Verwendung execzum Bearbeiten von Dateideskriptoren ist ein separates Thema. Die akzeptierte Antwort deckt das gut ab; Um dies in sich geschlossen zu halten, werde ich nur auf das Handbuch zurückgreifen, execwenn eine Umleitung anstelle eines Befehlsnamens folgt.

Tripleee
quelle
2
Widerstehen Sie der Versuchung, Ihre eigene schicke Muschel zu nennen bush. Dies gilt natürlich auch für bashoder allgemein für jede beliebte Unix-Shell. Wie @anishsane bemerkt , optimiert Bash heimlich, bash -c 'command'indem er es tatsächlich tut exec command.
Tripleee
1
Der Exit-Code der Shell ist im Allgemeinen der Exit-Code des zuletzt ausgeführten Befehls. Wenn die Shell nicht ausgeführt oder der Befehl nicht ausgeführt werden kann, spiegelt der Exit-Status der Shell dies natürlich mit einem geeigneten Fehlercode wider.
Tripleee
2
@ JonathanLeffler Ich dokumentiere absichtlich ein Antimuster, das ich in Fragen von Neulingen sehe. Dieser wurde durch dieses Duplikat veranlasst, aber ich habe es schon einmal gesehen, deshalb wollte ich das speziell behandeln.
Tripleee
2
@ JonathanLeffler Kleinere Formulierungsänderungen; ist das ausreichend, denkst du? Danke für die Rückmeldung.
Tripleee
2
Danke - ich habe einen weiteren kurzen Absatz über diese Optimierung hinzugefügt. Mir ist nicht wirklich klar, ob Sie andere Einwände haben oder nur Dinge aus einem anderen Blickwinkel erklären möchten.
Tripleee