Ich sehe dies am Anfang der Python-Dateien:
-
Für Python 2-Dateien
#!/usr/bin/env python
-
Für Python 3-Dateien
#!/usr/bin/env python3
Ich habe den Eindruck, dass die Dateien auch ohne diese Zeile funktionieren.
Ich sehe dies am Anfang der Python-Dateien:
Für Python 2-Dateien
#!/usr/bin/env python
Für Python 3-Dateien
#!/usr/bin/env python3
Ich habe den Eindruck, dass die Dateien auch ohne diese Zeile funktionieren.
Wenn Sie mehrere Versionen von Python installiert haben, /usr/bin/env
stellt sicher, dass der verwendete Interpreter der erste ist, der in der Liste Ihrer Umgebung $PATH
. Die Alternative wäre, etwas zu codieren wie #!/usr/bin/python
; das ist in Ordnung, aber weniger flexibel.
Unter Unix ist ein ausführbar Datei, die interpretiert werden soll, kann angeben, welchen Interpreter sie verwenden soll, indem sie eine #!
am Anfang der ersten Zeile, gefolgt von dem Interpreter (und den eventuell benötigten Flags).
Für andere Plattformen gilt diese Regel natürlich nicht (aber die "Shebang-Zeile" kann nicht schaden und ist hilfreich, wenn Sie das Skript jemals auf eine andere Plattform kopieren mit eine Unix-Basis, wie Linux, Mac usw.).
Dies wird als die Schlagzeile . Als die Der Wikipedia-Eintrag erklärt :
In der Informatik bezieht sich ein Shebang (auch Hashbang, Hashpling, Poundbang oder Crunchbang genannt) auf die Zeichen "#!", wenn sie die ersten beiden Zeichen in einer Interpreteranweisung 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 Interpreter auszuführen, der durch den Rest der ersten Zeile in der Datei angegeben ist.
Siehe auch die Unix-FAQ-Eintrag .
Selbst unter Windows, wo die shebang-Zeile nicht den auszuführenden Interpreter bestimmt, können Sie dem Interpreter Optionen übergeben, indem Sie sie in der shebang-Zeile angeben. Ich finde es nützlich, eine generische shebang-Zeile in einmaligen Skripten (wie denen, die ich schreibe, wenn ich Fragen auf SO beantworte) beizubehalten, damit ich sie schnell sowohl unter Windows als auch unter ArchLinux .
En Umgebungsdienstprogramm ermöglicht es Ihnen, einen Befehl auf dem Pfad aufzurufen:
Das erste verbleibende Argument gibt den aufzurufenden Programmnamen an; er wird gemäß der
PATH
Umgebungsvariable. Alle verbleibenden Argumente werden als Argumente an dieses Programm übergeben.
Um ein wenig auf die anderen Antworten einzugehen, hier ein kleines Beispiel, wie Ihre Befehlszeilenskripte durch unvorsichtige Verwendung von /usr/bin/env
Zeilen:
$ /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 existiert nicht in Python 2.5.
Eine Möglichkeit, sich gegen diese Art von Problemen zu schützen, ist die Verwendung der versionierten Python-Befehlsnamen, die 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 eine python3
Name:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
Um das Python-Skript ausführen zu können, müssen wir der Shell drei Dinge mitteilen:
Das ganze Paket #!
vollzieht (1.). Der Reigen beginnt mit einer #
weil die #
Zeichen ist in vielen Skriptsprachen eine Kommentar-Markierung. Der Inhalt der Shebang-Zeile wird daher vom Interpreter automatisch ignoriert.
En env
Befehl erfüllt (2.) und (3.). An Zitat "grawity,"
Eine häufige Verwendung des
env
Befehl ist es, Interpreter zu starten, indem man dass env in $PATH nach dem Befehl sucht, den es starten soll. gestartet werden soll. Da die shebang-Zeile die Angabe eines absoluten Pfades angegeben werden muss, und da der Ort der verschiedenen Interpreter (Perl, Bash, python) sehr unterschiedlich sein kann, ist es üblich, diese zu verwenden:
#!/usr/bin/env perl
anstatt zu versuchen 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/MrDaniel/usr/bin/perl auf dem System des Benutzers System...Andererseits befindet sich env fast immer in /usr/bin/env. (Außer in Fällen, in denen dies nicht der Fall ist; einige Systeme können /bin/env verwenden, aber das ist ein aber das ist ein ziemlich seltener Fall und kommt nur auf Nicht-Linux-Systemen vor).
En exec
Systemaufruf des Linux-Kernels versteht Shebangs ( #!
) von Haus aus
Wenn Sie auf Bash:
./something
unter Linux, ruft dies die exec
Systemaufruf mit dem Pfad ./something
.
Diese Zeile des Kernels wird für die Datei aufgerufen, die an exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Er liest die allerersten Bytes der Datei und vergleicht sie mit #!
.
Wenn der Vergleich wahr ist, wird der Rest der Zeile vom Linux-Kernel geparst, der eine weitere exec
rufen Sie mit:
/usr/bin/env
python
daher gleichbedeutend mit:
/usr/bin/env python /path/to/script.py
env
ist eine ausführbare Datei, die die PATH
um z.B. zu finden /usr/bin/python
und ruft dann schließlich an:
/usr/bin/python /path/to/script.py
Der Python-Interpreter sieht die #!
Zeile in der Datei, sondern #
ist das Kommentarzeichen in Python, also wird diese Zeile einfach als normaler Kommentar ignoriert.
Und ja, man kann eine Endlosschleife mit machen:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Die Bash erkennt den Fehler:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
nur zufällig für Menschen lesbar ist, aber das ist nicht erforderlich.
Wenn die Datei mit anderen Bytes beginnt, dann wird die exec
Systemaufruf würde einen anderen Handler verwenden. Der andere wichtige eingebaute Handler ist für ausführbare ELF-Dateien: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 die nach Bytes sucht 7f 45 4c 46
(die auch für Menschen lesbar ist .ELF
). Bestätigen wir das, indem wir die ersten 4 Bytes von /bin/ls
die eine ausführbare ELF-Datei ist:
head -c 4 "$(which ls)" | hd
Ausgabe:
00000000 7f 45 4c 46 |.ELF|
00000004
Wenn der Kernel also diese Bytes sieht, nimmt er die ELF-Datei, legt sie korrekt im Speicher ab und startet einen neuen Prozess damit. Siehe auch: Wie bekommt der Kernel eine ausführbare Binärdatei unter Linux zum Laufen?
Schließlich können Sie Ihre eigenen Shebang-Handler mit der Option binfmt_misc
Mechanismus. Zum Beispiel können Sie eine benutzerdefinierter Handler für .jar
Dateien . Dieser Mechanismus unterstützt sogar Handler nach Dateierweiterung. Eine weitere Anwendung ist Transparentes Ausführen von Programmen auf einer anderen Architektur mit QEMU .
Ich glaube nicht, dass POSIX spezifiziert jedoch Shebangs: https://unix.stackexchange.com/a/346214/32558 Obwohl es in den Begründungsabschnitten und in der Form "wenn ausführbare Skripte vom System unterstützt werden, kann etwas passieren" erwähnt wird. macOS und FreeBSD scheinen es jedoch auch zu implementieren.
PATH
Suchmotivation
Eine wichtige Motivation für die Existenz von Shebangs ist wahrscheinlich die Tatsache, dass wir in Linux oft Befehle von PATH
so wie:
basename-of-command
anstelle von:
/full/path/to/basename-of-command
Aber wie würde Linux ohne den Shebang-Mechanismus wissen, wie es die einzelnen Dateitypen starten soll?
Festcodierung der Erweiterung in Befehlen:
basename-of-command.py
oder die Implementierung der PATH-Suche auf jedem Interpreter:
python basename-of-command
wäre eine Möglichkeit, aber das hat das große Problem, dass alles kaputt geht, wenn wir uns jemals dazu entschließen, den Befehl in eine andere Sprache umzuformulieren.
Shebangs lösen dieses Problem hervorragend.
Wichtigster Anwendungsfall von env
: pyenv
und andere Versionsverwalter
Ein wichtiger Anwendungsfall, warum Sie Folgendes verwenden sollten #!/usr/bin/env python
statt nur /usr/bin/python
i pyenv
.
pyenv
ermöglicht es Ihnen, mehrere Python-Versionen auf einem einzigen Rechner zu installieren, um andere Projekte ohne Virtualisierung besser reproduzieren zu können.
Dann verwaltet es die "aktuelle" Python-Version, indem es ihre Reihenfolge im PATH festlegt: z.B. wie hier gezeigt apt-get install für verschiedene Python-Versionen ein von pyenv verwalteter Python könnte sich befinden unter:
/home/ciro/.pyenv/shims/python
also bei weitem nicht so viel wie /usr/bin/python
die bei einigen Systemen über update-alternatives
Symlinks .
CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.