Also dachte ich, ich hätte ein gutes Verständnis dafür, führte aber nur einen Test durch (als Reaktion auf ein Gespräch, bei dem ich mit jemandem nicht einverstanden war) und stellte fest, dass mein Verständnis fehlerhaft ist ...
So detailliert wie möglich , was genau passiert , wenn ich eine Datei in meinem Shell ausführen? Was ich meine ist, wenn ich Folgendes eintippe : ./somefile some arguments
in meine Shell und somefile
die Eingabetaste drücke (und in der CWD vorhanden ist und ich über Lese- und Ausführungsberechtigungen verfüge somefile
), was passiert dann unter der Haube?
Ich dachte die Antwort wäre:
- Die Shell ruft syscall an
exec
und leitet den Pfad ansomefile
- Der Kernel überprüft
somefile
und überprüft die magische Nummer der Datei, um festzustellen, ob es sich um ein Format handelt, das der Prozessor verarbeiten kann - Wenn die magische Zahl angibt, dass die Datei ein Format hat, das der Prozessor ausführen kann, dann
- ein neuer Prozess wird angelegt (mit einem Eintrag in der Prozesstabelle)
somefile
wird gelesen / in den Speicher abgebildet. Ein Stack wird erstellt und die Ausführung springt zum Einstiegspunkt des Codes vonsomefile
, wobeiARGV
ein Array der Parameter (achar**
,["some","arguments"]
) initialisiert wird.
- Wenn die magische Zahl ein Shebang ist, wird
exec()
ein neuer Prozess wie oben beschrieben erzeugt. Als ausführbare Datei wird jedoch der Interpreter verwendet, auf den der Shebang (z. B./bin/bash
oder/bin/perl
) verweist, undsomefile
an den er weitergeleitet wirdSTDIN
- Wenn die Datei keine gültige magische Nummer hat, tritt ein Fehler wie "Ungültige Datei (falsche magische Nummer): Exec-Formatfehler" auf
Allerdings hat mir jemand gesagt, dass die Shell versucht, die Befehle auszuführen, wenn es sich bei der Datei um reinen Text handelt (als hätte ich etwas eingegeben) bash somefile
). Ich habe das nicht geglaubt, aber ich habe es einfach versucht, und es war richtig. Ich habe also offensichtlich einige Missverständnisse darüber, was hier tatsächlich passiert, und möchte die Mechanik verstehen.
Was genau passiert, wenn ich eine Datei in meiner Shell ausführe? (Soweit Detail zumutbar ist ...)
source somefile
unterscheidet sich jedoch stark von einem neuen Prozess, der von einem anderen gespalten wird./somefile
../somefile
dies dazu führen würde, dass Bash die Befehle ausführt,somefile
wenn die Datei keine magische Nummer hätte. Ich dachte, es würde nur einen Fehler anzeigen, und stattdessen scheint es effektivsource somefile
somefile
es sich um eine Textdatei handelt, eine neue Shell erstellt wird, wenn ich versuche, sie auszuführen. Eine Dateiecho $$
verhält sich anders, wenn ich sie im Vergleich zur Quelle ausführe.Antworten:
Die endgültige Antwort auf die Frage, wie Programme unter Linux ausgeführt werden, ist das Artikelpaar auf LWN.net mit dem überraschenden Titel Wie Programme ausgeführt werden und Wie Programme ausgeführt werden: ELF-Binärdateien . Der erste Artikel befasst sich kurz mit Skripten. (Genau genommen befindet sich die endgültige Antwort im Quellcode, diese Artikel sind jedoch einfacher zu lesen und enthalten Links zum Quellcode.)
Ein kleines Experimentieren zeigt, dass Sie so ziemlich alles richtig gemacht haben und dass die Ausführung einer Datei, die eine einfache Liste von Befehlen enthält, von der Shell erledigt werden muss. Die Manpage execve (2) enthält den Quellcode für ein Testprogramm. Wir werden das nutzen, um zu sehen, was ohne Shell passiert. Schreiben Sie zunächst ein Testskript
testscr1
mitund ein anderer
testscr2
, der nur enthältMachen Sie beide ausführbar und stellen Sie sicher, dass beide von einer Shell ausgeführt werden:
Versuchen Sie es jetzt erneut mit
execve
Sie es (vorausgesetzt, Sie haben es im aktuellen Verzeichnis erstellt):testscr1
läuft noch, abertestscr2
produziertDies zeigt, dass die Shell
testscr2
unterschiedlich behandelt. Das Skript selbst wird jedoch nicht verarbeitet/bin/sh
. dies kann durch Rohrleitungen überprüft werden ,testscr2
umless
:Auf meinem System bekomme ich
Wie Sie sehen, wurde die von mir verwendete Shell
zsh
gestartetless
und eine zweite Shellsh
(dash
auf meinem System), um das Skript auszuführen, das ausgeführt wurdepstree
. Inzsh
dieser wird durch behandeltzexecve
inSrc/exec.c
: Die Shell benutzt ,execve(2)
um zu versuchen , den Befehl auszuführen, und wenn das nicht funktioniert, liest es die Datei zu sehen , ob es eine shebang hat, ist es entsprechend der Verarbeitung (die die Kernel auch getan hat), und wenn die schlägt fehl, es wird versucht, die Datei mit auszuführensh
, solange kein Null-Byte aus der Datei gelesen wurde:bash
hat das gleiche Verhalten, implementiertexecute_cmd.c
mit einem hilfreichen Kommentar (wie von taliezin hervorgehoben ):POSIX definiert einen Satz von Funktionen, wie bekannt die
exec(3)
Funktionen , die Wickelexecve(2)
und auch diese Funktionalität bereitzustellen; siehe muru ‚s Antwort für Details. Zumindest unter Linux werden diese Funktionen von der C-Bibliothek implementiert, nicht vom Kernel.quelle
Dies hängt zum Teil von der jeweiligen
exec
Familienfunktion ab, die verwendet wird.execve
Wie Stephen Kitt ausführlich gezeigt hat, werden nur Dateien im richtigen Binärformat oder Skripten ausgeführt, die mit einem richtigen Shebang beginnen.Allerdings ,
execlp
undexecvp
noch einen Schritt weiter gehen: Wenn die shebang nicht korrekt sind, wird die Datei mit ausgeführt/bin/sh
unter Linux. Vonman 3 exec
:Dies wird in gewisser Weise von POSIX (Schwerpunkt Mine) unterstützt:
Dies gibt nicht an, wie der Befehlsinterpreter abgerufen wird, gibt jedoch nicht an, dass ein Fehler angegeben werden muss. Ich vermute daher, dass die Linux-Entwickler solche Dateien laufen ließen
/bin/sh
(oder dies war bereits eine gängige Praxis und sie folgten einfach dem Beispiel).FWIW, die FreeBSD-Manpage,
exec(3)
erwähnt auch ein ähnliches Verhalten:AFAICT verwendet jedoch keine gemeinsame Shell
execlp
oderexecvp
direkt, vermutlich zur feineren Kontrolle über die Umgebung. Sie alle implementieren dieselbe Logik mitexecve
.quelle
execl
,execlp
,execle
,execv
,execvp
undexecvpe
sind alle Frontends an dieexecve
syscall; Erstere werden von der C-Bibliothek bereitgestellt, über die der Kernel nur Bescheid weißexecve
(undexecveat
heutzutage).Dies könnte eine Ergänzung zur Antwort von Stephen Kitt sein, als Kommentar aus der
bash
Quelle in der Dateiexecute_cmd.c
:quelle
Es wird als Shell-Skript ausgeführt, es wird nicht bezogen (z. B. wirken sich in der ausgeführten Datei gesetzte Variablen nicht auf die Umgebung aus). Vermutlich ein Überbleibsel aus der nebligen Vergangenheit, als es eine Shell und ein ausführbares Format gab. Keine ausführbare Datei, es muss ein Shell-Skript sein.
quelle
exec()
oder die Muschel? Ich möchte deutlich mehr Interna