Was macht ein "exec" -Befehl?

108

Ich verstehe den Bash-Befehl nicht exec. Ich habe gesehen, dass es in Skripten verwendet wird, um alle Ausgaben in eine Datei umzuleiten (wie in diesem Beispiel gezeigt ). Aber ich verstehe nicht, wie es funktioniert oder was es im Allgemeinen tut. Ich habe die Manpages gelesen, verstehe sie aber nicht.

becko
quelle
Kennen Sie einen Prozess ?
Fkraiem
1
@fkraiem was meinst du?
Becko
Entschuldigung, ich meinte "was". : p Aber die Antwort scheint nein zu sein.
Fkraiem
Aber tatsächlich nutzt Ihr Skript execeine spezielle Art und Weise, die viel einfacher erklärt werden kann, ich werde eine Antwort schreiben.
Fkraiem
1
Related: unix.stackexchange.com/q/296838/85039
Sergiy Kolodyazhnyy

Antworten:

88

man bash sagt:

exec [-cl] [-a name] [command [arguments]]
      If command is specified, it replaces the shell.  No new  process
      is  created.  The arguments become the arguments to command.  If
      the -l option is supplied,  the  shell  places  a  dash  at  the
      beginning  of  the  zeroth  argument passed to command.  This is
      what login(1) does.  The -c option causes command to be executed
      with  an empty environment.  If -a is supplied, the shell passes
      name as the zeroth argument to the executed command.  If command
      cannot  be  executed  for  some  reason, a non-interactive shell
      exits, unless the execfail shell option  is  enabled.   In  that
      case,  it returns failure.  An interactive shell returns failure
      if the file cannot be executed.  If command  is  not  specified,
      any  redirections  take  effect  in  the  current shell, and the
      return status is 0.  If there is a redirection error, the return
      status is 1.

Die letzten beiden Zeilen sind wichtig: Wenn Sie execohne Befehl von selbst ausführen , werden die Umleitungen einfach auf die aktuelle Shell angewendet. Sie wissen wahrscheinlich , dass , wenn Sie laufen command > file, der Ausgang commandgeschrieben wird , fileanstatt zu Ihrem Terminal (das eine genannt wird Umleitung ). Wenn Sie exec > filestattdessen ausführen , gilt die Umleitung für die gesamte Shell: Jede Ausgabe, die von der Shell erzeugt wird, filewird auf Ihr Terminal anstatt auf dieses geschrieben . Zum Beispiel hier

bash-3.2$ bash
bash-3.2$ exec > file
bash-3.2$ date
bash-3.2$ exit
bash-3.2$ cat file
Thu 18 Sep 2014 23:56:25 CEST

Ich starte zuerst eine neue bashShell. Dann starte ich in dieser neuen Shell exec > file, damit alle Ausgaben umgeleitet werden file. Zwar laufe ich danach dateaber ich bekomme keine Ausgabe, weil die Ausgabe umgeleitet wird file. Dann beende ich meine Shell (damit die Umleitung nicht mehr gilt) und sehe, dass sie filetatsächlich die Ausgabe des datezuvor ausgeführten Befehls enthält .

fkraiem
quelle
42
Dies ist nur eine teilweise Erklärung. execDient auch dazu, den aktuellen Shell-Prozess durch einen Befehl zu ersetzen, sodass die Eltern einen Weg gehen und das Kind die pid besitzt. Dies dient nicht nur der Umleitung. Bitte fügen Sie diese Information hinzu
Sergiy Kolodyazhnyy
3
Nach dem Kommentar von @ SergiyKolodyazhnyy ist das Beispiel, auf das ich gerade gestoßen bin und das mich zu dieser Seite geführt hat, ein docker-entrypoint.sh, bei dem nach dem Ausführen verschiedener Aktionen in der nginx-Konfiguration die letzte Zeile des Skripts ist exec nginx <various nginx arguments>. Dies bedeutet, dass Nginx die PID des Bash-Skripts übernimmt und jetzt Nginx der Hauptausführungsprozess des Containers ist, nicht das Skript. Ich nehme an, dies dient nur der Sauberkeit, es sei denn, jemand anderes kennt einen konkreteren Grund dafür?
Luke Griffiths
1
@Luke Dies wird "Wrapper-Skript" genannt. Beispiel dafür ist auch gnome-terminal, das zumindest am 14.04 ein Wrapper-Skript hatte, um Argumente einzurichten. Und das ist ihr einziger Zweck, wirklich - gesetzte Künste und Umwelt. Ein anderer Fall wäre, aufzuräumen - die vorherige Instanz eines Prozesses zuerst zu
beenden
Ein weiteres execBeispiel, das dem nginxBeispiel von @LukeGriffiths ähnelt, ist das ~/.vnc/xstartupSkript, vncservermit dem ein VNC-Serverprozess konfiguriert wird, und dann exec gnome-sessionoder exec startkdeund so weiter.
Trevor Boyd Smith
@LukeGriffiths, der Hauptgrund für execein Container-Startskript, ist, dass die PID 1, der ENTRYPOINT des Containers, in Docker eine besondere Bedeutung hat. Es ist ein Hauptprozess, der Signale empfängt, und wenn er existiert, verlässt er auch den Container. execNur eine Möglichkeit, shdiese Befehlskette zu verlassen und den Daemon zum Hauptprozess des Containers zu machen.
km,
46

exec ist ein Befehl mit zwei sehr unterschiedlichen Verhaltensweisen, je nachdem, ob mindestens ein Argument oder gar kein Argument verwendet wird.

  • Wenn mindestens ein Argument übergeben wird, wird das erste als Befehlsname verwendet und execversucht, es als Befehl auszuführen, indem die verbleibenden Argumente an diesen Befehl übergeben und die Umleitungen, falls vorhanden, verwaltet werden.

  • Wenn der als erstes Argument übergebene Befehl nicht vorhanden ist, wird die aktuelle Shell, nicht nur der Befehl exec, fehlerhaft beendet.

  • Wenn der Befehl vorhanden und ausführbar ist, ersetzt er die aktuelle Shell. Das bedeutet, dass execdie Anweisungen, die auf den exec-Aufruf folgen , niemals ausgeführt werden , wenn sie in einem Skript erscheinen (es execsei denn, sie befinden sich selbst in einer Subshell). execkehrt nie zurück. Shell-Traps wie "EXIT" werden ebenfalls nicht ausgelöst.

  • Wenn kein Argument übergeben wird, execwerden nur die aktuellen Shell-Dateideskriptoren neu definiert. Die Shell wird im execGegensatz zum vorherigen Fall nach dem fortgesetzt , aber die Standardeingabe, die Standardausgabe, der Standardfehler oder der umgeleitete Dateideskriptor werden wirksam.

  • Wenn einige der Umleitungen verwendet werden /dev/null, werden alle Eingaben von EOF zurückgegeben und alle Ausgaben verworfen.

  • Sie können Dateideskriptoren schließen, indem Sie -als Quelle oder Ziel verwenden, z exec <&-. Nachfolgende Lese- oder Schreibvorgänge schlagen dann fehl.

Hier sind zwei Beispiele:

echo foo > /tmp/bar
exec < /tmp/bar # exec has no arguments, will only affect current shell descriptors, here stdin
cat # simple command that read stdin and write it to stdout

Dieses Skript gibt "foo" als cat-Befehl aus, anstatt auf Benutzereingaben zu warten, wie dies im Normalfall der Fall gewesen wäre. Die Eingabe erfolgt aus der Datei / tmp / bar, die foo enthält.

echo foo > /tmp/bar
exec wc -c < /tmp/bar # exec has two arguments, the control flow will switch to the wc command
cat

Dieses Skript wird angezeigt 4(die Anzahl der Bytes in / tmp / bar) und endet sofort. Der catBefehl wird nicht ausgeführt.

jlliagre
quelle
4
`Einige alte Beiträge werden nie wirklich alt ... +1.
Cbhihe
3
Wenn einige der Umleitungen / dev / null verwenden, wird der zugehörige Dateideskriptor geschlossen. Nein, es wird wirklich zu / von umgeleitet /dev/null, sodass Schreibvorgänge weiterhin erfolgreich sind und Return-EOF gelesen werden. close(2)Auf einem fd würden Systemaufrufe mit Lese- / Schreibzugriff Fehler zurückgeben, und Sie tun dies exec 2>&-beispielsweise mit.
Peter Cordes
2
Probieren Sie es selbst exec 3</dev/null; ls -l /proc/self/fd:: Beachten Sie, dass fd 3 unter / dev / null schreibgeschützt geöffnet ist. Dann schließe es wieder mit exec 3<&-, und du siehst ( ls -l /proc/$$/fdwieder mit), dass dein Shell-Prozess kein fd 3 mehr hat. (Das Schließen von stdin mit exec <&-kann in Skripten nützlich sein, aber interaktiv ist es eine Abmeldung.)
Peter Cordes
@PeterCordes Sie haben absolut Recht. Antwort aktualisiert. Vielen Dank!
jlliagre
1
Diese Antwort ist großartig, weil sie erklärt, dass die beiden Anwendungsfälle execder aktuell am häufigsten bewerteten Antwort nur den einen Anwendungsfall und die andere Antwort von g_p nur den anderen Anwendungsfall betreffen. Und diese Antwort ist für solch ein komplexes Thema nett und präzise / lesbar.
Trevor Boyd Smith
33

Um zu verstehen exec, müssen Sie zuerst verstehen fork. Ich versuche es kurz zu halten.

  • Wenn Sie zu einer Weggabelung kommen, haben Sie im Allgemeinen zwei Möglichkeiten. Linux-Programme erreichen diese Weggabelung, wenn sie auf einen fork()Systemaufruf stoßen.

  • Normale Programme sind Systembefehle, die in kompilierter Form auf Ihrem System vorhanden sind. Wenn ein solches Programm ausgeführt wird, wird ein neuer Prozess erstellt. Dieser untergeordnete Prozess hat dieselbe Umgebung wie sein übergeordneter Prozess, nur die Prozess-ID unterscheidet sich. Dieser Vorgang wird als Gabeln bezeichnet .

  • Durch das Verzweigen kann ein vorhandener Prozess einen neuen Prozess starten. Es kann jedoch Situationen geben, in denen ein untergeordneter Prozess nicht Teil desselben Programms wie der übergeordnete Prozess ist. In diesem Fall execwird verwendet. exec ersetzt den Inhalt des aktuell ausgeführten Prozesses durch die Informationen aus einer Programm-Binärdatei.
  • Nach dem Verzweigungsprozess wird der Adressraum des untergeordneten Prozesses mit den neuen Prozessdaten überschrieben. Dies geschieht durch einen Exec-Aufruf an das System.
g_p
quelle
3
Kannst du erklären, warum execeine Skriptausgabe umgeleitet werden kann, wie in dem von mir geposteten Link?
Becko
1
Ich fand dies unklar "Es kann jedoch Situationen geben, in denen ein
untergeordneter
6

In bash, wenn du tust help exec:

$ help exec
exec: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
    Replace the shell with the given command.

    Execute COMMAND, replacing this shell with the specified program.
    ARGUMENTS become the arguments to COMMAND.  If COMMAND is not specified,
    any redirections take effect in the current shell.

    Options:
      -a name   pass NAME as the zeroth argument to COMMAND
      -c        execute COMMAND with an empty environment
      -l        place a dash in the zeroth argument to COMMAND

    If the command cannot be executed, a non-interactive shell exits, unless
    the shell option `execfail' is set.

    Exit Status:
    Returns success unless COMMAND is not found or a redirection error occurs.

Das relevante Bit:

If COMMAND is not specified, any redirections take effect in the current shell.

execist eine eingebaute Shell , die das Shell-Äquivalent der execFamilie von Systemaufrufen ist , von denen G_P spricht (und deren Hilfeseiten Sie offenbar gelesen haben). Es hat nur die von POSIX vorgeschriebene Funktionalität, die aktuelle Shell zu beeinflussen, wenn kein Befehl angegeben wird.

muru
quelle