Woher weiß / usr / bin / env, welches Programm verwendet werden soll?

62

Woher #!/usr/bin/env pythonweiß das System, wenn ich mit dem shebang ein Skript ausführe, welches pythonzu verwenden ist? Wenn ich pythonin den Umgebungsvariablen nach einem bin-Pfad suche, finde ich nichts.

env | grep -i python
tMC
quelle
6
oh, ich glaube, ich habe es herausgefunden - es durchsucht nur Ihren $ PATH nach 'Python'
tMC
Darüber habe ich mich auch gewundert. Und warum / usr / bin / env? im Gegensatz zu / bin / env oder env, wenn es nur eine Liste von Pfaden von env abruft?
Faheem Mitha
Nur 'env' wird nicht funktionieren, weil es der vollständige Pfad sein muss. Das Programm 'env' befindet sich normalerweise in / user / bin / env. In einigen Distributionen kann es auch als / bin / env gefunden werden, aber es ist sicherer, mit / usr / bin / env zu arbeiten.
rettops

Antworten:

54

Der Shebang erwartet, dass ein vollständiger Pfad zum Interpreter verwendet wird, sodass die folgende Syntax falsch wäre:

#!python

So kann ein vollständiger Pfad festgelegt werden:

#!/usr/local/bin/python

aber wäre nicht tragbar als Python könnte installiert /bin, /opt/python/binanderen Ort, oder wo auch immer.

Verwenden env

#!/usr/bin/env python

ist eine Methode, mit der auf tragbare Weise dem Betriebssystem ein vollständiger Pfad angegeben werden kann, der dem Pfad entspricht, in dem sich der Pfad pythonzuerst befindet PATH.

jlliagre
quelle
56

Die Shebang- Linie (also von "sharp bang" #!) wird vom Kernel verarbeitet. Der Kernel möchte nichts über Umgebungsvariablen wie wissen PATH. Der Name in der shebang-Zeile muss also ein absoluter Pfad zu einer ausführbaren Datei sein. Sie können auch ein zusätzliches Argument angeben, das vor dem Skriptnamen an die ausführbare Datei übergeben wird (mit systemabhängigen Einschränkungen, auf die ich hier nicht eingehen werde). Beispielsweise können Sie für ein Python-Skript angeben

#!/usr/bin/python

In der ersten Zeile und wenn Sie das Skript ausführen, wird der Kernel tatsächlich ausgeführt /usr/bin/python /path/to/script. Dies ist jedoch nicht bequem: Sie müssen den vollständigen Pfad des Befehls angeben. Was passiert , wenn Sie pythonin /usr/binauf einigen Rechnern und /usr/local/binauf andere? Oder möchten Sie festlegen PATH, /home/joe/opt/python-2.5/bindass eine bestimmte Version von Python verwendet wird? Da der Kernel die PATHSuche nicht für Sie übernimmt , besteht die Idee darin, den Kernel dazu zu bringen, einen Befehl auszuführen, der den gewünschten Interpreter in den PATHfolgenden Abschnitten nachschlägt :

#!/fixed/path/to/path-lookup-command python

Das path-lookup-commandmuss den Namen einer ausführbaren Datei als Argument nehmen und nachschlagen PATHund ausführen: Der Kernel wird ausgeführt /fixed/path/to/path-lookup-command python /path/to/script. Der envBefehl macht genau das. Der Hauptzweck besteht darin, einen Befehl in einer anderen Umgebung auszuführen. Da jedoch der Befehlsname $PATHdarin nachgeschlagen wird, ist er für unseren Zweck hier perfekt.

Obwohl dies nicht offiziell garantiert ist, haben historische Unix-Systeme, die envin /usr/binund modernen Systemen bereitgestellt werden, diesen Ort genau wegen der weit verbreiteten Verwendung von beibehalten #!/usr/bin/env. In der Praxis können Sie also festlegen, dass ein Skript vom bevorzugten Python-Interpreter des Benutzers ausgeführt werden muss

#!/usr/bin/env python
Gilles 'SO - hör auf böse zu sein'
quelle
2
welches ist zwischen envund bevorzugt which? Seitdem wird auch die am besten geeignete ausführbare Datei aus meiner PATH-Umgebung abgerufen.
Nikhil Mulley
8
@NikhilMulley whichfindet die ausführbare Datei und druckt ihren Pfad. envFindet das durch das erste Argument angegebene Programm und führt es aus, wobei die restlichen Argumente übergeben werden.
Kevin
3
so ist es, dass enveine Evaluierungsversion von im whichWesentlichen ist.
Nikhil Mulley
6

Richtig, so laufen:

env | grep PATH

Ihr $ PATH ist eine Liste von Verzeichnissen. Unix durchsucht diese Verzeichnisliste der Reihe nach, bis es "python" findet.

Mit dem Befehl 'which' können Sie sehen, welches Verzeichnis gefunden wird:

which python
Dan Rue
quelle
Interessanterweise sehe ich einen Unterschied in der Python sys.pathzwischen einem aktivierten env $ env python3 ( ['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']) und ./env/bin/python3 (['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/test/env3/lib/python3.4/site-packages']).
ThorSummoner