Ist es möglich, dass ein Shebang den Namen des Interpreters enthält und die Shell ihn über $ PATH findet, anstatt einen Pfad zu einem Interpreter anzugeben?
PATH-Lookup ist eine Funktion der Standard-C-Bibliothek im Benutzerbereich, ebenso wie Umgebungsvariablen im Allgemeinen. Der Kernel sieht keine Umgebungsvariablen, es sei denn, er übergibt eine Umgebung vom Aufrufer execvean den neuen Prozess.
Der Kernel führt keine Interpretation des Pfades in execve(es liegt an den Wrapper-Funktionen, wie zum Beispiel execvpder PATH-Suche) oder in einem Shebang (der den execveAnruf mehr oder weniger intern umleitet) durch. Sie müssen also den absoluten Pfad in den shebang¹ setzen. Die ursprüngliche shebang-Implementierung bestand nur aus wenigen Codezeilen und wurde seitdem nicht wesentlich erweitert.
In den ersten Versionen von Unix hat die Shell sich selbst aufgerufen, als sie bemerkte, dass Sie ein Skript aufgerufen haben. Shebang wurde aus mehreren Gründen in den Kernel aufgenommen (Zusammenfassung der Begründung von Dennis Ritchie :
Der Aufrufer muss sich keine Sorgen machen, ob ein auszuführendes Programm ein Shell-Skript oder eine native Binärdatei ist.
Das Skript selbst gibt an, welcher Interpreter anstelle des Aufrufers verwendet werden soll.
Der Kernel verwendet den Skriptnamen in Protokollen.
Pathless Shebangs müssten entweder den Kernel erweitern, um auf Umgebungsvariablen und -prozesse zuzugreifen PATH, oder den Kernel ein Userspace-Programm ausführen lassen, das die PATH-Suche durchführt. Die erste Methode erfordert das Hinzufügen einer unverhältnismäßigen Menge an Komplexität zum Kernel. Die zweite Methode ist bereits mit einem #!/usr/bin/envShebang möglich .
¹ Wenn Sie einen relativen Pfad angeben, wird dieser relativ zum aktuellen Verzeichnis des Prozesses interpretiert (nicht zum Verzeichnis, in dem sich das Skript befindet), was in einem Shebang kaum sinnvoll ist.
Nein, der Kernel benötigt weder einen absoluten Pfad in execvenoch im Shebang, obwohl es wenig sinnvoll ist, einen relativen Pfad in einem Shebang zu haben.
Stéphane Chazelas
3
Für alle, die neugierig sind, wie "shebang den execve-Aufruf intern umleitet": Dies ist Teil eines generischen Mechanismus zum Ausführen von Interpretern für ausführbare Dateien, die diese benötigen. Dynamisch verknüpfte ELF-Executables werden von "interpretiert" /lib64/ld-linux-x86-64.so.2(siehe lddAusgabe). Linux macht es vollständig generisch: Mit der binfmtUnterstützung (seit 2.1.43) können Sie Interpreter-Pfad / Magic-Number-or-File-Extension-Paare registrieren. Sie können PE32s .exeaufrufen, winewenn Sie sie ausführen, Java-Klassen- und JAR-Dateien aufrufen javausw. usw.
Peter Cordes
#! / usr / bin / env -S [shebang] war erforderlich, damit ich den Knoten ausführen konnte, ohne seinen Pfad zu kennen (mithilfe von nvm - wodurch er an einem anderen Ort als ursprünglich erwartet abgelegt wird).
Es ist mehr los als man denkt. #!Zeilen werden vom Unix- oder Linux-Kernel interpretiert, #!sind aber kein Aspekt von Shells. Dies bedeutet, dass PATHes zu dem Zeitpunkt, an dem der Kernel entscheidet, was ausgeführt werden soll , nicht wirklich existiert.
Die gebräuchlichste Möglichkeit, nicht zu wissen, welche ausführbare Datei ausgeführt werden soll, oder auf perltragbare Weise oder auf ähnliche Weise aufzurufen , ist die Verwendung von #!/usr/bin/env perl. Der Kernel wird ausgeführt /usr/bin/env, der eine PATHUmgebungsvariable erbt . envfindet (in diesem Beispiel) perlin PATHund verwendet den execve(2)Systemaufruf, um den Kernel zum Ausführen der perlausführbaren Datei zu veranlassen.
$ strace sleep 1
execve("/usr/bin/sleep",["sleep","1"],[/*99 vars */])=0
Die Konvertierung in den vollständigen Pfad erfolgt über die Shell (allgemeiner: im Userspace). Der Kernel erwartet einen Dateinamen / Pfad, auf den er direkt zugreifen kann.
Wenn Sie möchten, dass das System Ihre ausführbare Datei durch Durchsuchen der PATH-Variablen findet, können Sie Ihren shebang als umschreiben #!/usr/bin/env EXEC.
Aber auch in diesem Fall ist es nicht der Kernel, der die Suche durchführt.
Die Konvertierung in den vollständigen Pfad erfolgt über die Shell. Danke, obwohl ... das Beispiel dies veranschaulichen soll? Wie ich es sehe, läuft die Shell nur strace( /usr/bin/straceirgendwann konvertiert ) mit 2 Argumenten.
Antworten:
PATH-Lookup ist eine Funktion der Standard-C-Bibliothek im Benutzerbereich, ebenso wie Umgebungsvariablen im Allgemeinen. Der Kernel sieht keine Umgebungsvariablen, es sei denn, er übergibt eine Umgebung vom Aufrufer
execve
an den neuen Prozess.Der Kernel führt keine Interpretation des Pfades in
execve
(es liegt an den Wrapper-Funktionen, wie zum Beispielexecvp
der PATH-Suche) oder in einem Shebang (der denexecve
Anruf mehr oder weniger intern umleitet) durch. Sie müssen also den absoluten Pfad in den shebang¹ setzen. Die ursprüngliche shebang-Implementierung bestand nur aus wenigen Codezeilen und wurde seitdem nicht wesentlich erweitert.In den ersten Versionen von Unix hat die Shell sich selbst aufgerufen, als sie bemerkte, dass Sie ein Skript aufgerufen haben. Shebang wurde aus mehreren Gründen in den Kernel aufgenommen (Zusammenfassung der Begründung von Dennis Ritchie :
Pathless Shebangs müssten entweder den Kernel erweitern, um auf Umgebungsvariablen und -prozesse zuzugreifen
PATH
, oder den Kernel ein Userspace-Programm ausführen lassen, das die PATH-Suche durchführt. Die erste Methode erfordert das Hinzufügen einer unverhältnismäßigen Menge an Komplexität zum Kernel. Die zweite Methode ist bereits mit einem#!/usr/bin/env
Shebang möglich .¹ Wenn Sie einen relativen Pfad angeben, wird dieser relativ zum aktuellen Verzeichnis des Prozesses interpretiert (nicht zum Verzeichnis, in dem sich das Skript befindet), was in einem Shebang kaum sinnvoll ist.
quelle
execve
noch im Shebang, obwohl es wenig sinnvoll ist, einen relativen Pfad in einem Shebang zu haben./lib64/ld-linux-x86-64.so.2
(sieheldd
Ausgabe). Linux macht es vollständig generisch: Mit derbinfmt
Unterstützung (seit 2.1.43) können Sie Interpreter-Pfad / Magic-Number-or-File-Extension-Paare registrieren. Sie können PE32s.exe
aufrufen,wine
wenn Sie sie ausführen, Java-Klassen- und JAR-Dateien aufrufenjava
usw. usw.Es ist mehr los als man denkt.
#!
Zeilen werden vom Unix- oder Linux-Kernel interpretiert,#!
sind aber kein Aspekt von Shells. Dies bedeutet, dassPATH
es zu dem Zeitpunkt, an dem der Kernel entscheidet, was ausgeführt werden soll , nicht wirklich existiert.Die gebräuchlichste Möglichkeit, nicht zu wissen, welche ausführbare Datei ausgeführt werden soll, oder auf
perl
tragbare Weise oder auf ähnliche Weise aufzurufen , ist die Verwendung von#!/usr/bin/env perl
. Der Kernel wird ausgeführt/usr/bin/env
, der einePATH
Umgebungsvariable erbt .env
findet (in diesem Beispiel)perl
inPATH
und verwendet denexecve(2)
Systemaufruf, um den Kernel zum Ausführen derperl
ausführbaren Datei zu veranlassen.quelle
Die Konvertierung in den vollständigen Pfad erfolgt über die Shell (allgemeiner: im Userspace). Der Kernel erwartet einen Dateinamen / Pfad, auf den er direkt zugreifen kann.
Wenn Sie möchten, dass das System Ihre ausführbare Datei durch Durchsuchen der PATH-Variablen findet, können Sie Ihren shebang als umschreiben
#!/usr/bin/env EXEC
.Aber auch in diesem Fall ist es nicht der Kernel, der die Suche durchführt.
quelle
strace
(/usr/bin/strace
irgendwann konvertiert ) mit 2 Argumenten.