Mir scheint, dass die Dateien ohne diese Zeile gleich laufen.
Mir scheint, dass die Dateien ohne diese Zeile gleich laufen.
Antworten:
Wenn Sie mehrere Versionen von Python installiert haben, stellen Sie /usr/bin/env
sicher , dass der verwendete Interpreter der erste in Ihrer Umgebung ist $PATH
. Die Alternative wäre, so etwas wie fest zu codieren #!/usr/bin/python
; das ist ok, aber weniger flexibel.
Unter Unix kann eine ausführbare Datei, die interpretiert werden soll, angeben, welcher Interpreter verwendet werden soll, indem #!
am Anfang der ersten Zeile ein gefolgt vom Interpreter (und eventuell benötigten Flags) steht.
Wenn Sie über andere Plattformen sprechen, gilt diese Regel natürlich nicht (aber diese "Shebang-Linie" schadet nicht und hilft, wenn Sie dieses Skript jemals auf eine Plattform mit einer Unix-Basis wie Linux oder Mac kopieren , usw).
chmod +x myscript.py
) und dann direkt ausführen : ./myscript.py
anstatt nur python myscript.py
.
env
bietet maximale Flexibilität, da der Benutzer den zu verwendenden Interpreter durch Ändern des Pfads auswählen kann. Oft ist diese Flexibilität jedoch nicht erforderlich, und der Nachteil ist, dass Linux beispielsweise den Skriptnamen nicht für den Namen des Prozesses in verwenden kann ps
und zu "Python" zurückkehrt. Wenn Sie beispielsweise Python-Apps für Distributionen verpacken, würde ich davon abraten, diese zu verwenden env
.
py
Launcher kann die Shebang-Linie unter Windows verwenden. Es ist in Python 3.3 enthalten oder kann unabhängig installiert werden .
/usr/bin/env: Key has expired
Nach vielen Stunden starben jedoch Prozesse mit der Nachricht .
Das nennt man die Shebang-Linie . Wie der Wikipedia-Eintrag erklärt :
Beim Rechnen bezieht sich ein Shebang (auch Hashbang, Hashpling, Pound Bang oder Crunchbang genannt) auf die Zeichen "#!" wenn sie die ersten beiden Zeichen in einer Interpreter-Direktive als erste Zeile einer Textdatei sind. In einem Unix-ähnlichen Betriebssystem nimmt der Programmlader das Vorhandensein dieser beiden Zeichen als Hinweis darauf, dass es sich bei der Datei um ein Skript handelt, und versucht, dieses Skript mit dem in der restlichen ersten Zeile der Datei angegebenen Interpreter auszuführen.
Siehe auch den Unix-FAQ-Eintrag .
Selbst unter Windows, wo die Shebang-Zeile den auszuführenden Interpreter nicht bestimmt, können Sie Optionen an den Interpreter übergeben, indem Sie sie in der Shebang-Zeile angeben. Ich finde es nützlich, eine generische Shebang-Zeile in einmaligen Skripten zu behalten (wie die, die ich bei der Beantwortung von Fragen zu SO schreibe), damit ich sie sowohl unter Windows als auch unter ArchLinux schnell testen kann .
Mit dem Dienstprogramm env können Sie einen Befehl für den Pfad aufrufen:
Das erste verbleibende Argument gibt den aufzurufenden Programmnamen an. Es wird nach der
PATH
Umgebungsvariablen gesucht . Alle verbleibenden Argumente werden als Argumente an dieses Programm übergeben.
Im Folgenden finden Sie ein kleines Beispiel dafür, wie Ihre Befehlszeilenskripte durch unachtsame Verwendung von /usr/bin/env
Shebang-Zeilen in Schwierigkeiten geraten können:
$ /usr/local/bin/python -V
Python 2.6.4
$ /usr/bin/python -V
Python 2.5.1
$ cat my_script.py
#!/usr/bin/env python
import json
print "hello, json"
$ PATH=/usr/local/bin:/usr/bin
$ ./my_script.py
hello, json
$ PATH=/usr/bin:/usr/local/bin
$ ./my_script.py
Traceback (most recent call last):
File "./my_script.py", line 2, in <module>
import json
ImportError: No module named json
Das json-Modul ist in Python 2.5 nicht vorhanden.
Eine Möglichkeit, sich vor solchen Problemen zu schützen, besteht darin, die versionierten Python-Befehlsnamen zu verwenden, die normalerweise mit den meisten Pythons installiert werden:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Wenn Sie nur zwischen Python 2.x und Python 3.x unterscheiden müssen, bieten neuere Versionen von Python 3 auch einen python3
Namen:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
zurückgegeben wird /usr/bin/python
, kann ein lokaler Verzeichnispfad fest codiert sein : #!/usr/bin/python
. Das ist jedoch weniger flexibel als #!/usr/bin/env python
bei einer globalen Anwendung.
Um das Python-Skript auszuführen, müssen wir der Shell drei Dinge mitteilen:
Der Shebang #!
schafft (1.). Der Shebang beginnt mit einem, #
weil das #
Zeichen in vielen Skriptsprachen ein Kommentar-Marker ist. Der Inhalt der Shebang-Zeile wird daher vom Interpreter automatisch ignoriert.
Der env
Befehl führt (2.) und (3.) aus. Um "Grawity" zu zitieren:
Eine häufige Verwendung des
env
Befehls besteht darin, Interpreter zu starten, indem die Tatsache ausgenutzt wird, dass env $ PATH nach dem Befehl durchsucht, den es starten soll. Da für die Shebang-Linie ein absoluter Pfad angegeben werden muss und die Position verschiedener Interpreter (Perl, Bash, Python) sehr unterschiedlich sein kann, wird häufig Folgendes verwendet:
#!/usr/bin/env perl
anstatt zu erraten, ob es sich um / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl oder / home handelt / MrDaniel / usr / bin / perl auf dem System des Benutzers ...Andererseits befindet sich env fast immer in / usr / bin / env. (Außer in Fällen, in denen dies nicht der Fall ist. Einige Systeme verwenden möglicherweise / bin / env, dies ist jedoch ziemlich selten und tritt nur auf Nicht-Linux-Systemen auf.)
Vielleicht ist Ihre Frage in diesem Sinne:
Wenn Sie verwenden möchten: $python myscript.py
Sie brauchen diese Zeile überhaupt nicht. Das System ruft Python auf und dann führt der Python-Interpreter Ihr Skript aus.
Aber wenn Sie beabsichtigen zu verwenden: $./myscript.py
Wenn Sie es direkt wie ein normales Programm oder ein Bash-Skript aufrufen, müssen Sie diese Zeile schreiben, um dem System anzugeben, mit welchem Programm es ausgeführt wird (und um es auch ausführbar zu machen chmod 755
).
Der exec
Systemaufruf des Linux-Kernels versteht shebangs ( #!
) nativ
Wenn Sie auf Bash tun:
./something
Unter Linux ruft dies den exec
Systemaufruf mit dem Pfad auf ./something
.
Diese Zeile des Kernels wird in der Datei aufgerufen, die an folgende Adresse übergeben wird exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Es liest die ersten Bytes der Datei und vergleicht sie mit #!
.
Wenn der Vergleich wahr ist, wird der Rest der Zeile vom Linux-Kernel analysiert, der einen weiteren exec
Aufruf mit Pfad /usr/bin/env python
und aktueller Datei als erstem Argument ausführt:
/usr/bin/env python /path/to/script.py
Dies funktioniert für jede Skriptsprache, die #
als Kommentarzeichen verwendet wird.
Und ja, Sie können eine Endlosschleife erstellen mit:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash erkennt den Fehler:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
zufällig menschlich lesbar, aber das ist nicht erforderlich.
Wenn die Datei mit unterschiedlichen Bytes gestartet exec
würde, würde der Systemaufruf einen anderen Handler verwenden. Der andere wichtigste integrierte Handler ist für ausführbare ELF-Dateien: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305, der nach Bytes sucht 7f 45 4c 46
(die ebenfalls menschlich sind) lesbar für .ELF
). Lassen Sie uns dies bestätigen, indem Sie die 4 ersten Bytes von lesen /bin/ls
, bei denen es sich um eine ausführbare ELF-Datei handelt:
head -c 4 "$(which ls)" | hd
Ausgabe:
00000000 7f 45 4c 46 |.ELF|
00000004
Wenn der Kernel diese Bytes sieht, nimmt er die ELF-Datei, speichert sie korrekt und startet damit einen neuen Prozess. Siehe auch: Wie erhält der Kernel eine ausführbare Binärdatei, die unter Linux ausgeführt wird?
Schließlich können Sie mit dem binfmt_misc
Mechanismus Ihre eigenen Shebang-Handler hinzufügen . Sie können beispielsweise einen benutzerdefinierten Handler für .jar
Dateien hinzufügen . Dieser Mechanismus unterstützt sogar Handler nach Dateierweiterung. Eine andere Anwendung besteht darin , ausführbare Dateien einer anderen Architektur mit QEMU transparent auszuführen .
Ich glaube nicht, dass POSIX Shebangs spezifiziert: https://unix.stackexchange.com/a/346214/32558 , obwohl es in Begründungsabschnitten und in der Form "Wenn ausführbare Skripte vom System unterstützt werden, kann etwas erwähnt werden." geschehen". macOS und FreeBSD scheinen es jedoch auch zu implementieren.
PATH
Suchmotivation
Eine große Motivation für die Existenz von Shebangs ist wahrscheinlich die Tatsache, dass wir unter Linux häufig Befehle ausführen möchten, und zwar aus folgenden Gründen PATH
:
basename-of-command
anstatt:
/full/path/to/basename-of-command
Aber wie würde Linux dann ohne den Shebang-Mechanismus wissen, wie jeder Dateityp gestartet wird?
Hardcodierung der Erweiterung in Befehlen:
basename-of-command.py
oder Implementieren der PATH-Suche auf jedem Interpreter:
python basename-of-command
wäre eine Möglichkeit, aber dies hat das Hauptproblem, dass alles kaputt geht, wenn wir uns jemals dazu entschließen, den Befehl in eine andere Sprache umzugestalten.
Shebangs lösen dieses Problem wunderbar.
Technisch gesehen ist dies in Python nur eine Kommentarzeile.
Diese Zeile wird nur verwendet, wenn Sie das py-Skript über die Shell (über die Befehlszeile) ausführen . Dies ist bekannt als " Shebang !" und es wird in verschiedenen Situationen verwendet, nicht nur mit Python-Skripten.
Hier wird die Shell angewiesen, eine bestimmte Version von Python zu starten (um den Rest der Datei zu erledigen.
py.exe
. Dies ist Teil einer Standard-Python-Installation.
Der Hauptgrund dafür ist, das Skript in Betriebssystemumgebungen portierbar zu machen.
Beispielsweise verwenden Python-Skripte unter mingw Folgendes:
#!/c/python3k/python
und unter GNU / Linux-Distribution ist es entweder:
#!/usr/local/bin/python
oder
#!/usr/bin/python
und unter dem besten kommerziellen Unix-SW / HW-System von allen (OS / X) ist es:
#!/Applications/MacPython 2.5/python
oder auf FreeBSD:
#!/usr/local/bin/python
All diese Unterschiede können das Skript jedoch für alle portierbar machen, indem Folgendes verwendet wird:
#!/usr/bin/env python
/usr/bin/python
. Unter Linux ist der vom System installierte Python mit ziemlicher Sicherheit auch /usr/bin/python
(ich habe noch nie etwas anderes gesehen und es würde keinen Sinn ergeben). Beachten Sie, dass es möglicherweise Systeme gibt, die keine haben /usr/bin/env
.
python
ist nicht so portabel, sondern der Standard-Python-Interpreter für die Distribution. Arch Linux verwendet standardmäßig lange Zeit Python 3 und möglicherweise denken auch Distributionen darüber nach, da Python 2 nur bis 2020 unterstützt wird.
Es ist wahrscheinlich sinnvoll, eine Sache hervorzuheben, die die meisten übersehen haben, was ein sofortiges Verständnis verhindern kann. Wenn Sie python
ein Terminal eingeben, geben Sie normalerweise keinen vollständigen Pfad an. Stattdessen wird die ausführbare Datei in der PATH
Umgebungsvariablen nachgeschlagen . Wenn Sie ein Python-Programm direkt ausführen möchten /path/to/app.py
, müssen Sie der Shell mitteilen, welcher Interpreter verwendet werden soll (über den Hashbang , was die anderen Mitwirkenden oben erklären).
Hashbang erwartet den vollständigen Pfad zu einem Dolmetscher. Um Ihr Python-Programm direkt auszuführen, müssen Sie daher den vollständigen Pfad zur Python-Binärdatei angeben , der erheblich variiert, insbesondere unter Berücksichtigung der Verwendung von virtualenv . Um die Portabilität anzugehen, wird der Trick mit /usr/bin/env
verwendet. Letzteres soll ursprünglich die Umgebung an Ort und Stelle ändern und einen Befehl darin ausführen. Wenn keine Änderung vorgenommen wird, wird der Befehl in der aktuellen Umgebung ausgeführt, was effektiv zu derselben PATH
Suche führt, die den Trick ausführt.
Dies ist eine Shell-Konvention, die der Shell mitteilt, welches Programm das Skript ausführen kann.
#! / usr / bin / env python
wird in einen Pfad zur Python-Binärdatei aufgelöst.
Es wird empfohlen, wie in der Dokumentation vorgeschlagen:
2.2.2. Ausführbare Python-Skripte
Auf BSD'ish Unix-Systemen können Python-Skripte wie Shell-Skripte direkt ausführbar gemacht werden, indem die Zeile eingefügt wird
#! /usr/bin/env python3.2
von http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Sie können dieses Problem mit virtualenv versuchen
Hier ist test.py.
#! /usr/bin/env python
import sys
print(sys.version)
Erstellen Sie virtuelle Umgebungen
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
Aktivieren Sie jede Umgebung und überprüfen Sie die Unterschiede
echo $PATH
./test.py
Es gibt nur an, welchen Interpreter Sie verwenden möchten. Um dies zu verstehen, erstellen Sie eine Datei über das Terminal, touch test.py
und geben Sie dann Folgendes in diese Datei ein:
#!/usr/bin/env python3
print "test"
und tun chmod +x test.py
, um Ihr Skript ausführbar zu machen. Danach ./test.py
sollten Sie eine Fehlermeldung erhalten, die besagt:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
weil python3 den Druckoperator nicht unterstützt.
Ändern Sie nun die erste Zeile Ihres Codes in:
#!/usr/bin/env python2
und es wird funktionieren, test
wenn auf stdout gedruckt wird , da python2 den Druckoperator unterstützt. Jetzt haben Sie gelernt, wie Sie zwischen Skriptinterpreten wechseln.
Mir scheint, dass die Dateien ohne diese Zeile gleich laufen.
Wenn ja, führen Sie das Python-Programm möglicherweise unter Windows aus? Windows verwendet diese Zeile nicht. Stattdessen wird die Dateinamenerweiterung verwendet, um das mit der Dateierweiterung verknüpfte Programm auszuführen.
Im Jahr 2011 wurde jedoch ein "Python-Launcher" entwickelt, der (bis zu einem gewissen Grad) dieses Linux-Verhalten für Windows nachahmt. Dies beschränkt sich nur auf die Auswahl des ausgeführten Python-Interpreters, z. B. auf Python 2 und Python 3 auf einem System, auf dem beide installiert sind. Der Launcher wird optional wie py.exe
bei der Python-Installation installiert und kann mit .py
Dateien verknüpft werden, sodass der Launcher diese Zeile überprüft und die angegebene Python-Interpreter-Version startet.
$ python myscript.py
.
Dies ist eher eine historische Information als eine "echte" Antwort.
Denken Sie daran , dass wieder in den Tag Sie viele Unix hatte wie Betriebssysteme , deren Designer alle hatten ihre eigene Vorstellung davon , wo Sachen zu setzen, und manchmal haben sind nicht Python, Perl, Bash, oder viele andere GNU / Open Source Sachen überhaupt .
Dies galt sogar für verschiedene Linux-Distributionen. Unter Linux - vor FHS [1] - haben Sie möglicherweise Python in / usr / bin / oder / usr / local / bin /. Oder es wurde möglicherweise nicht installiert, also haben Sie Ihr eigenes erstellt und in ~ / bin abgelegt
Solaris war das Schlimmste, an dem ich je gearbeitet habe, teilweise als Übergang von Berkeley Unix zu System V. Sie könnten mit Sachen in / usr /, / usr / local /, / usr / ucb, / opt / usw. fertig werden für einige wirklich lange Wege. Ich habe Erinnerungen an das Zeug von Sunfreeware.com, das jedes Paket in einem eigenen Verzeichnis installiert, aber ich kann mich nicht erinnern, ob es die Binärdateien mit / usr / bin verknüpft hat oder nicht.
Oh, und manchmal war / usr / bin auf einem NFS-Server [2].
Daher wurde das env
Dienstprogramm entwickelt, um dies zu umgehen.
Dann konnte man schreiben #!/bin/env interpreter
und solange der Weg richtig war, hatten die Dinge eine vernünftige Chance zu rennen. Vernünftig bedeutete natürlich (für Python und Perl), dass Sie auch die entsprechenden Umgebungsvariablen festgelegt hatten. Für bash / ksh / zsh hat es einfach funktioniert.
Dies war wichtig, da die Leute Shell-Skripte (wie Perl und Python) weitergaben und wenn Sie / usr / bin / python auf Ihrer Red Hat Linux-Workstation fest codiert hatten, würde dies auf einer SGI schlecht funktionieren ... na ja, nein Ich denke, IRIX hat Python an die richtige Stelle gebracht. Aber auf einer Sparc-Station läuft es möglicherweise überhaupt nicht.
Ich vermisse meine Sparc Station. Aber nicht viele. Ok, jetzt troll ich auf E-Bay herum. Bastagen.
[1] Dateisystem-Hierarchiestandard. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Ja, und manchmal machen die Leute immer noch solche Sachen. Und nein, ich habe weder eine Rübe noch eine Zwiebel am Gürtel getragen.
Wenn Sie Ihr Skript beispielsweise in einer virtuellen Umgebung venv
ausführen, wird which python
beim Ausführen während der Arbeit venv
der Pfad zum Python-Interpreter angezeigt:
~/Envs/venv/bin/python
Beachten Sie, dass der Name der virtuellen Umgebung in den Pfad zum Python-Interpreter eingebettet ist . Daher führt das Hardcodieren dieses Pfads in Ihrem Skript zu zwei Problemen:
Um Jonathans Antwort zu ergänzen , ist der ideale Schebang #!/usr/bin/env python
nicht nur für die Portabilität zwischen Betriebssystemen, sondern auch für die Portabilität in virtuellen Umgebungen!
In Anbetracht der Portabilitätsprobleme zwischen python2
und python3
sollten Sie immer eine der beiden Versionen angeben, es sei denn, Ihr Programm ist mit beiden kompatibel.
Einige Distributionen werden versendet python
einiger Zeit mit Symlinks versehen python3
- verlassen Sie sich nicht darauf, python
dass Sie es sind python2
.
Dies wird durch betont PEP 394 hervorgehoben :
Um Unterschiede zwischen den Plattformen zu tolerieren, sollte der gesamte neue Code, der den Python-Interpreter aufrufen muss, nicht Python angeben, sondern entweder Python2 oder Python3 (oder die spezifischeren Versionen von Python2.x und Python3.x; siehe Migrationshinweise ). . Diese Unterscheidung sollte in Shebangs getroffen werden, wenn über ein Shell-Skript aufgerufen wird, wenn über den Aufruf system () aufgerufen wird oder wenn in einem anderen Kontext aufgerufen wird.
Hier können Sie die ausführbare Datei auswählen, die Sie verwenden möchten. Dies ist sehr praktisch, wenn Sie möglicherweise mehrere Python-Installationen und verschiedene Module in jedem haben und auswählen möchten. z.B
#!/bin/sh
#
# Choose the python we need. Explanation:
# a) '''\' translates to \ in shell, and starts a python multi-line string
# b) "" strings are treated as string concat by python, shell ignores them
# c) "true" command ignores its arguments
# c) exit before the ending ''' so the shell reads no further
# d) reset set docstrings to ignore the multiline comment code
#
"true" '''\'
PREFERRED_PYTHON=/Library/Frameworks/Python.framework/Versions/2.7/bin/python
ALTERNATIVE_PYTHON=/Library/Frameworks/Python.framework/Versions/3.6/bin/python3
FALLBACK_PYTHON=python3
if [ -x $PREFERRED_PYTHON ]; then
echo Using preferred python $ALTERNATIVE_PYTHON
exec $PREFERRED_PYTHON "$0" "$@"
elif [ -x $ALTERNATIVE_PYTHON ]; then
echo Using alternative python $ALTERNATIVE_PYTHON
exec $ALTERNATIVE_PYTHON "$0" "$@"
else
echo Using fallback python $FALLBACK_PYTHON
exec python3 "$0" "$@"
fi
exit 127
'''
__doc__ = """What this file does"""
print(__doc__)
import platform
print(platform.python_version())
Dies teilt dem Skript mit, wo sich das Python-Verzeichnis befindet.
#! /usr/bin/env python
#!/usr/bin/env python
oben anzeigt .