Warum nicht pathless shebangs verwenden?

Antworten:

20

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.

Gilles 'SO - hör auf böse zu sein'
quelle
2
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).
TamusJRoyce
-S ist erst ab Coreutils 8.30 verfügbar. Siehe gitlab.com/gnuwget/wget/commit/… .
Tim Ruehsen rockdaboot
19

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.

Bruce Ediger
quelle
4
$ 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.

Hauke ​​Laging
quelle
1
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.
Alois Mahdal