Die Antwort darunter besagt, dass es sich nur um eine Kommentarzeile handelt. Das ist nicht immer der Fall. Ich habe ein "Hallo Welt!" CGI-Skript (.py), das nur ausgeführt wird und die Webseite #!/usr/bin/env pythonoben anzeigt .
Sie können laufen, aber nicht in der vorgesehenen Umgebung
Nicholas Hamilton
18
Ich habe diesen Beitrag in 7 Jahren so oft besucht, weil ich manchmal den env hashbang vergesse. Nudeln kopieren :)
BugHunterUK
Antworten:
1082
Wenn Sie mehrere Versionen von Python installiert haben, stellen Sie /usr/bin/envsicher , 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).
Nur zum Hinzufügen: Dies gilt, wenn Sie es unter Unix ausführen, indem Sie es ausführbar machen ( chmod +x myscript.py) und dann direkt ausführen : ./myscript.pyanstatt nur python myscript.py.
Craig McQueen
28
Die Verwendung envbietet 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 psund zu "Python" zurückkehrt. Wenn Sie beispielsweise Python-Apps für Distributionen verpacken, würde ich davon abraten, diese zu verwenden env.
Ein wichtiges Wort der Warnung: Der Rückgabewert von env läuft schließlich ab. Was Sie wahrscheinlich nicht betrifft, wenn Sie kurzlebige Prozesse ausführen. /usr/bin/env: Key has expiredNach vielen Stunden starben jedoch Prozesse mit der Nachricht .
Malaverdiere
4
@malaverdiere Können Sie Links zu Ressourcen erstellen, die dieses Ablaufverhalten erklären? Ich kann sie nicht finden.
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.
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 PATHUmgebungsvariablen gesucht . Alle verbleibenden Argumente werden als Argumente an dieses Programm übergeben.
Mit Google leicht zu finden - wenn man die Keywords kennt (Die "Shebang-Linie" ist unerlässlich).
Arafangion
14
Tatsächlich ist diese Erklärung klarer als andere Referenzen, die ich bei Google überprüft habe. Es ist immer schöner, eine Erklärung in einem Absatz zu erhalten, die auf die Frage abzielt, als ein ganzes Handbuch zu lesen, das sich mit jeder möglichen Verwendung befasst.
@ulidtko: Interessante Suchmaschine, überlegen Sie, eine Antwort zu schreiben, damit John Garcias 'Frage eine bessere Antwort hat.
Arafangion
1
"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." Das ist einfach falsch; Wenn so etwas passiert, liegt es daran, dass der Interpreter selbst die Shebang-Zeile verarbeitet. Wenn der Dolmetscher keine besondere Anerkennung für Shebang-Zeilen hat, passiert so etwas nicht. Windows macht nichts mit Shebang-Zeilen. "Was Sie in diesem Fall möglicherweise beschreiben, ist der Python-Launcher: python.org/dev/peps/pep-0397 .
Kaz
154
Im Folgenden finden Sie ein kleines Beispiel dafür, wie Ihre Befehlszeilenskripte durch unachtsame Verwendung von /usr/bin/envShebang-Zeilen in Schwierigkeiten geraten können:
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:
Hmm, das habe ich aus diesem Beitrag nicht herausgeholt.
Glenn Jackman
1
Unterschied zwischen lokal und global. Wenn which pythonzurückgegeben wird /usr/bin/python, kann ein lokaler Verzeichnispfad fest codiert sein : #!/usr/bin/python. Das ist jedoch weniger flexibel als #!/usr/bin/env pythonbei einer globalen Anwendung.
Noobninja
85
Um das Python-Skript auszuführen, müssen wir der Shell drei Dinge mitteilen:
Dass die Datei ein Skript ist
Welchen Interpreter möchten wir das Skript ausführen?
Der Weg des Dolmetschers
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 envBefehl führt (2.) und (3.) aus. Um "Grawity" zu zitieren:
Eine häufige Verwendung des envBefehls 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.)
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).
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 execAufruf mit Pfad /usr/bin/env pythonund 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 execwü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:
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.
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.
Der Shebang ist ein Unix-Konzept. Erwähnenswert ist, dass es auch unter Windows funktioniert, wenn Sie den Python-Launcher installiert haben py.exe. Dies ist Teil einer Standard-Python-Installation.
Florida
38
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:
Unter MacOSX ist es auch /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.
Albert
1
Wenn Sie unter OSX arbeiten und Homebrew verwenden und die Standardinstallationsanweisungen befolgen, finden Sie diese unter #! / Usr / local / bin / python
Wird
@ Jean-PaulCalderone: Siehe Saajs Antwort unten.
Pydsigner
Update für das Jahr 2018: Bare pythonist 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.
mati865
22
Es ist wahrscheinlich sinnvoll, eine Sache hervorzuheben, die die meisten übersehen haben, was ein sofortiges Verständnis verhindern kann. Wenn Sie pythonein Terminal eingeben, geben Sie normalerweise keinen vollständigen Pfad an. Stattdessen wird die ausführbare Datei in der PATHUmgebungsvariablen 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/envverwendet. 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 PATHSuche führt, die den Trick ausführt.
Es gibt nur an, welchen Interpreter Sie verwenden möchten. Um dies zu verstehen, erstellen Sie eine Datei über das Terminal, touch test.pyund geben Sie dann Folgendes in diese Datei ein:
#!/usr/bin/env python3print"test"
und tun chmod +x test.py, um Ihr Skript ausführbar zu machen. Danach ./test.pysollten Sie eine Fehlermeldung erhalten, die besagt:
File"./test.py", line 2print"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, testwenn 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.exebei der Python-Installation installiert und kann mit .pyDateien verknüpft werden, sodass der Launcher diese Zeile überprüft und die angegebene Python-Interpreter-Version startet.
Ich habe den Fehler gemacht, indem ich die Zeile nicht hatte und python script.py verwendet habe. Eines Tages habe ich einfach ./myscript.py verwendet und alles hat aufgehört zu funktionieren. Dann wurde mir klar, dass das System die Datei als Shell-Skript anstelle eines Python-Skripts betrachtet.
Guagua
8
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 envDienstprogramm entwickelt, um dies zu umgehen.
Dann konnte man schreiben #!/bin/env interpreterund 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.
Wenn Sie Ihr Skript beispielsweise in einer virtuellen Umgebung venvausführen, wird which pythonbeim Ausführen während der Arbeit venvder 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:
Wenn Sie das Skript in ein Repository hochladen, zwingen Sie andere Benutzer, denselben Namen für die virtuelle Umgebung zu verwenden . Dies ist der Fall, wenn sie das Problem zuerst identifizieren.
Sie können das Skript nicht in mehreren virtuellen Umgebungen ausführen, selbst wenn Sie alle erforderlichen Pakete in anderen virtuellen Umgebungen hatten.
Um Jonathans Antwort zu ergänzen , ist der ideale Schebang #!/usr/bin/env pythonnicht nur für die Portabilität zwischen Betriebssystemen, sondern auch für die Portabilität in virtuellen Umgebungen!
In Anbetracht der Portabilitätsprobleme zwischen python2und python3sollten 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, pythondass Sie es sind python2.
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())
#!/usr/bin/env python
oben anzeigt .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).
quelle
chmod +x myscript.py
) und dann direkt ausführen :./myscript.py
anstatt nurpython 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 kannps
und zu "Python" zurückkehrt. Wenn Sie beispielsweise Python-Apps für Distributionen verpacken, würde ich davon abraten, diese zu verwendenenv
.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 :
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:
quelle
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: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:
Wenn Sie nur zwischen Python 2.x und Python 3.x unterscheiden müssen, bieten neuere Versionen von Python 3 auch einen
python3
Namen:quelle
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:quelle
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
).quelle
Der
exec
Systemaufruf des Linux-Kernels versteht shebangs (#!
) nativWenn Sie auf Bash tun:
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#L25Es 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:Dies funktioniert für jede Skriptsprache, die
#
als Kommentarzeichen verwendet wird.Und ja, Sie können eine Endlosschleife erstellen mit:
Bash erkennt den Fehler:
#!
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 sucht7f 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:Ausgabe:
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
SuchmotivationEine 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
:anstatt:
Aber wie würde Linux dann ohne den Shebang-Mechanismus wissen, wie jeder Dateityp gestartet wird?
Hardcodierung der Erweiterung in Befehlen:
oder Implementieren der PATH-Suche auf jedem Interpreter:
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.
quelle
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.
quelle
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:
und unter GNU / Linux-Distribution ist es entweder:
oder
und unter dem besten kommerziellen Unix-SW / HW-System von allen (OS / X) ist es:
oder auf FreeBSD:
All diese Unterschiede können das Skript jedoch für alle portierbar machen, indem Folgendes verwendet wird:
quelle
/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 derPATH
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 derselbenPATH
Suche führt, die den Trick ausführt.Quelle von Unix StackExchange
quelle
Dies ist eine Shell-Konvention, die der Shell mitteilt, welches Programm das Skript ausführen kann.
wird in einen Pfad zur Python-Binärdatei aufgelöst.
quelle
Es wird empfohlen, wie in der Dokumentation vorgeschlagen:
von http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
quelle
Sie können dieses Problem mit virtualenv versuchen
Hier ist test.py.
Erstellen Sie virtuelle Umgebungen
Aktivieren Sie jede Umgebung und überprüfen Sie die Unterschiede
quelle
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:und tun
chmod +x test.py
, um Ihr Skript ausführbar zu machen. Danach./test.py
sollten Sie eine Fehlermeldung erhalten, die besagt:weil python3 den Druckoperator nicht unterstützt.
Ändern Sie nun die erste Zeile Ihres Codes in:
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.quelle
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.quelle
$ 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.
quelle
Wenn Sie Ihr Skript beispielsweise in einer virtuellen Umgebung
venv
ausführen, wirdwhich python
beim Ausführen während der Arbeitvenv
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!quelle
In Anbetracht der Portabilitätsprobleme zwischen
python2
undpython3
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 versehenpython3
- verlassen Sie sich nicht darauf,python
dass Sie es sindpython2
.Dies wird durch betont PEP 394 hervorgehoben :
quelle
Es teilt dem Interpreter mit, mit welcher Python-Version das Programm ausgeführt werden soll, wenn Sie über mehrere Python-Versionen verfügen.
quelle
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
quelle
Dies teilt dem Skript mit, wo sich das Python-Verzeichnis befindet.
quelle