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?
Wenn nicht, gibt es einen Grund dafür?
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?
Wenn nicht, gibt es einen Grund dafür?
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 Beispiel execvp
der PATH-Suche) oder in einem Shebang (der den execve
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.
execve
noch im Shebang, obwohl es wenig sinnvoll ist, einen relativen Pfad in einem Shebang zu haben.
/lib64/ld-linux-x86-64.so.2
(siehe ldd
Ausgabe). Linux macht es vollständig generisch: Mit der binfmt
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 aufrufen java
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, dass PATH
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 eine PATH
Umgebungsvariable erbt . env
findet (in diesem Beispiel) perl
in PATH
und verwendet den execve(2)
Systemaufruf, um den Kernel zum Ausführen der perl
ausfü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.
strace
( /usr/bin/strace
irgendwann konvertiert ) mit 2 Argumenten.