Brauchen Sie Erklärungen für Linux Bash in exec Befehlsverhalten
Vom Bash Reference Manual bekomme ich die folgende über exec
bash-builtin-Kommando:
Falls Befehl angegeben wird, ersetzt es das Oberteil ohne erstellen eines neuen Prozesses.
Nun habe ich Folgendes bash
Skript:
#!/bin/bash
exec ls;
echo 123;
exit 0
Diese ausgeführt habe, bekam ich diese:
cleanup.sh ex1.bash file.bash file.bash~ output.log
(files from the current directory)
Nun, wenn ich dieses Skript:
#!/bin/bash
exec ls | cat
echo 123
exit 0
Bekomme ich die folgende Ausgabe:
cleanup.sh
ex1.bash
file.bash
file.bash~
output.log
123
Meine Frage ist:
Wenn exec
aufgerufen es ersetzt die shell ohne Erstellung eines neuen Prozesses, warum, wenn Sie gesetzt | cat
, die echo 123
gedruckt, aber ohne Sie ist es nicht. Also, ich würde mich freuen, wenn jemand erklären kann, was die Logik für dieses Verhalten ist.
Dank.
BEARBEITEN:
Nach @torek Antwort, bekomme ich ein noch schwerer zu erklären-Verhalten:
1.exec ls>out
Befehl erstellt die out
- Datei und legen Sie es in die ls
's Befehl Folge;
2.exec ls>out1 ls>out2
erstellt nur die Dateien, aber nicht in jeder Folge. Wenn der Befehl funktioniert wie vorgeschlagen, ich denke, der Befehl Nummer 2 müsste das gleiche Ergebnis wie der Befehl Nummer 1 (sogar noch mehr, ich denke, es sollte nicht erstellt hatte out2
- Datei).
exec
C exec
Funktion. Was Sie testen, ist der bash
exec
- Objekt. Sie sind nicht das gleiche. Sehen www.gnu.org/software/bash/manual/bashref.html InformationsquelleAutor der Frage artaxerxe | 2012-03-29
Du musst angemeldet sein, um einen Kommentar abzugeben.
In diesem speziellen Fall, haben Sie die
exec
in einer pipeline. Um das ausführen einer Reihe von pipeline-Befehle, die die shell muss zunächst der Gabel, wodurch eine sub-shell. (Genauer gesagt, es ist zu schaffen, das Rohr, dann die Gabel, so dass alles laufen "auf der linken Seite" des Rohres kann seine Ausgabe an, was "rechts" von der pipe.)Zu sehen, dass dies in der Tat, was passiert ist, zu vergleichen:
mit:
Ersteres läuft
ls
ohne die sub-shell, so dass dieser sub-shell ist daher immer noch rund zu laufenecho
. Letztere läuftls
durch verlassen der sub-shell, die ist deshalb nicht mehr dort zu tun, dieecho
, undthis too
wird nicht gedruckt.(Die Verwendung von geschweiften-Klammern
{ cmd1; cmd2; }
normalerweise unterdrückt die sub-shell-fork Aktion, die man mit Klammern(cmd1; cmd2)
, aber im Fall von ein Rohr, die Gabel ist "gezwungen", wie Sie waren.)Umleitung von der aktuellen shell passiert nur, wenn es "nichts laufen", wie es war, nach dem Wort
exec
. So, z.B.,exec >stdout 4<input 5>>append
ändert die aktuelle shell, aberexec foo >stdout 4<input 5>>append
versucht exec-Befehlfoo
. [Hinweis: dies ist streng genommen nicht richtig ist; siehe Nachtrag.]Interessant ist, in eine interaktive shell an, nach
exec foo >output
nicht, weil es kein Befehlfoo
die shell-sticks um, aber stdout bleibt weitergeleitet Dateioutput
. (Sie können wieder mitexec >/dev/tty
. In einem Skript, das scheitern zuexec foo
beendet das Skript.)Mit einem Tipp der Hut, um @Pumbaa80, hier noch etwas mehr veranschaulicht:
(Hinweis:
cat -E
vereinfacht runter von meiner üblichencat -vET
, das ist mein praktisches go-to für "lassen Sie mich sehen, nicht-Druck-Zeichen, die in einer erkennbaren Weise"). Wenn dieses Skript ausgeführt wird, die Ausgabe vonls
hatcat -E
angewendet (auf Linux macht das end-of-line-sichtbar als ein $ - Zeichen), aber die Ausgabe an stdout und stderr (auf den letzten beiden Zeilen) ist nicht umgeleitet. Ändern Sie die| cat -E
zu> out
und, nachdem das Skript ausgeführt wird, beachten Sie den Inhalt der Dateiout
: die letzten beidenecho
s sind nicht drin.Ändern Sie nun den
ls
zufoo
(oder einen anderen Befehl, der nicht gefunden werden) und führen Sie das Skript erneut. Dieses mal ist die Ausgabe:und die Datei
out
hat nun die Inhalte produziert, die von der erstenecho
Linie.Das macht, was
exec
"wirklich" so klar wie möglich (aber nicht mehr offensichtlich, als Albert Einstein hat es nicht 🙂 ).Normalerweise, wenn die shell geht zur Ausführung eines "einfachen Befehl" (siehe die manual-Seite für die genaue definition, aber dies schließt ausdrücklich die Befehle in einer "pipeline"), bereitet es jedem I/O-Umleitung Operationen angegeben mit
<
,>
, und so weiter durch das öffnen der-Dateien benötigt. Dann die shell ruftfork
(oder eine gleichwertige, aber effizientere Variante wievfork
oderclone
je nach zugrunde liegenden Betriebssystem, Konfiguration, etc.), und, in der Kind-Prozess, ordnet die offenen Datei-Deskriptoren (mitdup2
Anrufe oder gleichwertig), um die gewünschte endgültige Vereinbarungen:> out
bewegt sich der open-Deskriptor fd 1—stdout—während6> out
bewegt sich der open-Deskriptor fd 6.Wenn Sie angeben, die
exec
keyword, obwohl die shell unterdrückt diefork
Schritt. Unterstützt alle Datei-öffnen und Datei-Deskriptor-Neuordnung, wie üblich, aber diesmal es betrifft alle und alle nachfolgenden Befehle. Schließlich, nachdem Sie es getan haben alle Umleitungen die shell versuchtexecve()
(in der system-call-Sinn) der Befehl, falls es einer ist. Wenn es keinen Befehl, oder wenn dieexecve()
Aufruf fehlschlägt und die shell soll weiterhin ausführen (interaktiv oder Sie eingestellt habenexecfail
), die shell-Soldaten auf. Wenn dieexecve()
gelingt, die Schale ist nicht mehr vorhanden, wurde ersetzt durch das neue Kommando. Wennexecfail
nicht gesetzt ist und die shell nicht interaktiv ist, die shell beendet wird.(Es gibt auch den zusätzlichen Komplikation der
command_not_found_handle
shell-Funktion: bash istexec
scheint zu unterdrücken, läuft es, basierend auf Testergebnissen. Dieexec
keyword im Allgemeinen ist die shell nicht auf seine eigenen Funktionen, d.h., wenn Sie eine shell-Funktion f, ausgeführtf
als ein einfacher Befehl führt die shell-Funktion, wie(f)
läuft es in einer sub-shell, die aber mit(exec f)
überspringt.)Wie, warum
ls>out1 ls>out2
werden zwei Dateien erstellt (mit oder ohneexec
), das ist einfach genug: die Muschel öffnet jede Umleitung und verwendet danndup2
zu bewegen, die Datei-Deskriptoren. Wenn Sie zwei normale>
leitet die shell öffnet, bewegt sich der erste, fd 1 (stdout), dann bewegt sich die zweite fd 1 (stdout wieder), die Schließung des ersten in den Prozess. Endlich, es läuftls ls
, weil das, was übrig bleibt, nach dem entfernen der>out1 >out2
. Solange es keine Datei namensls
, diels
Befehl klagt auf stderr ab und schreibt nichts auf die Standardausgabe.InformationsquelleAutor der Antwort torek