AusDasLink: Ich erhalte Folgendes zum integrierten Befehl „exec bash“:
Wenn der Befehl angegeben wird,ersetzt die Schaleohne einen neuen Prozess zu erstellen.
Wie genau ersetzt es die Shell (d. h. wie funktioniert es intern)? Funktioniert der exec*()
Systemaufruf genauso?
Antwort1
Ja, das exec
integrierte Programm verwendet letztendlich einen der exec*()
Systemaufrufe. Dasselbe gilt für das normale Ausführen von Befehlen. Wenn Sie jedoch verwenden exec
, wird der Systemaufruf nicht fork()
zuerst verwendet, um einen neuen Prozess zu erstellen. Das Ergebnis ist, dass der neue Befehl die Shell ersetzt.
Antwort2
Ich habe dies strace
auf einer laufenden bash
Instanz durchgeführt. Dann habe ich den Befehl aufgerufen exec sleep 100
. Sehen Sie nun, was passiert ist:
access("/bin/sleep", X_OK) = 0
...
execve("/bin/sleep", ["sleep", "100"], [/* 14 vars */]) = 0
...
nanosleep({100, 0},
...
exit_group(0) = ?
Sie sehen also, dass es fast genauso abläuft wie beim sleep
normalen Aufruf. bash
Überprüft, ob die Ausführungsberechtigung ( X_OK
) für /bin/sleep
den access()
Systemaufruf erteilt wurde. execve()
Führt dann das Programm aus, auf das der Dateiname verweist. Nach execve()
dem Systemaufruf sleep
hat er die Kontrolle über den Prozess. Er macht folgende Dinge: nanosleep()
. Er behält auch die gleiche PID. Nach sleep
dem Ende endet auch der Prozess. Egal, sleep
ob bash
er nicht mehr läuft.
Beweis:
In einem weiteren Fenster habe ich den Vorgang mit verfolgt ps
. Vor dem Ausführen des Befehls sah es so aus:
$ ps -o stat,pid,cmd -p <pid>
Ss+ 10905 -bash
Und beim Laufen:
$ ps -o stat,pid,cmd -p <pid>
Ss+ 10905 sleep 100
Nach sleep
Abschluss des Vorgangs verschwand er.
Was passiert, wenn ich es normal ausführe?
access("/bin/sleep", X_OK) = 0
...
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f6c9fd089d0) = 19261
...
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 19261
...
--- SIGCHLD (Child exited) @ 0 (0) ---
Die Ausführungsberechtigung wird geprüft. Dann wird ein Kindprozess erzeugt clone()
. Die bash
Instanz befindet sich nun in der Hintergrundprozessgruppe, sleep
ist in der Vordergrundprozessgruppe. Und zum Schluss wait4()
wartet der Aufruf, bis der Kindprozess beendet ist (das dauert 100 Sekunden).