Het lijkt mij alsof de bestanden hetzelfde werken zonder die regel.
Antwoord 1, autoriteit 100%
Als je meerdere versies van Python hebt geïnstalleerd, zal /usr/bin/env
ervoor zorgen dat de gebruikte interpreter de eerste is op de $PATH
van je omgeving. Het alternatief zou zijn om iets als #!/usr/bin/python
te hardcoderen; dat is ok, maar minder flexibel.
In Unix kan een uitvoerbaar-bestand dat bedoeld is om te worden geïnterpreteerd, aangeven welke interpreter moet worden gebruikt door een #!
aan het begin van de eerste regel te plaatsen, gevolgd door de tolk (en eventuele vlaggen die het nodig heeft).
Als je het over andere platforms hebt, is deze regel natuurlijk niet van toepassing (maar die “shebang-regel” kan geen kwaad, en zal helpen als je dat script ooit naar een platform kopieert meteen Unix-basis, zoals Linux, Mac, enz.).
Antwoord 2, autoriteit 25%
Dat wordt de shebang-regelgenoemd. Zoals het Wikipedia-item uitlegt:
In computergebruik verwijst een shebang (ook wel hashbang, hashpling, pound bang of crunchbang genoemd) naar de tekens “#!” wanneer ze de eerste twee tekens in een tolkrichtlijn zijn als de eerste regel van een tekstbestand. In een Unix-achtig besturingssysteem neemt de programmalader de aanwezigheid van deze twee karakters als een indicatie dat het bestand een script is, en probeert dat script uit te voeren met behulp van de interpreter gespecificeerd door de rest van de eerste regel in het bestand.
Zie ook de Unix FAQ-invoer.
Zelfs in Windows, waar de shebang-regel niet bepaalt welke interpreter moet worden uitgevoerd, kunt u opties aan de interpreter doorgeven door ze op de shebang-regel te specificeren. Ik vind het handig om een generieke shebang-regel in eenmalige scripts te houden (zoals degene die ik schrijf bij het beantwoorden van vragen over SO), zodat ik ze snel kan testen op zowel Windows als ArchLinux.
Met het env-hulpprogrammakun je een commando op het pad aanroepen:
Het eerste overgebleven argument specificeert de programmanaam die moet worden aangeroepen; er wordt naar gezocht volgens de omgevingsvariabele
PATH
. Alle resterende argumenten worden als argumenten aan dat programma doorgegeven.
Antwoord 3, autoriteit 14%
Een beetje uitbreidend op de andere antwoorden, hier is een klein voorbeeld van hoe uw commandoregelscripts in de problemen kunnen komen door onvoorzichtig gebruik van /usr/bin/env
shebang-regels:
$ /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
De json-module bestaat niet in Python 2.5.
Een manier om u tegen dat soort problemen te beschermen, is door de python-opdrachtnamen met versiebeheer te gebruiken die doorgaans bij de meeste Pythons worden geïnstalleerd:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Als u alleen onderscheid moet maken tussen Python 2.x en Python 3.x, bieden recente releases van Python 3 ook een python3
-naam:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
Antwoord 4, autoriteit 8%
Om het python-script uit te voeren, moeten we de shell drie dingen vertellen:
- Dat het bestand een script is
- Welke interpreter we het script willen uitvoeren
- Het pad van de tolk
De kreng #!
volbrengt (1.). De shebang begint met een #
omdat het teken #
een commentaarmarkering is in veel scripttalen. De inhoud van de shebang-regel wordt daarom automatisch genegeerd door de interpreter.
De opdracht env
volbrengt (2.) en (3.). Om “dankbaarheid” te citeren
Een algemeen gebruik van de opdracht
env
is om tolken te starten door het maken van
gebruik van het feit dat env $PATH zal zoeken voor het commando dat wordt verteld
lanceren. Omdat de shebang-regel een absoluut pad vereist om te zijn
gespecificeerd, en aangezien de locatie van verschillende tolken (perl, bash,
python) kan veel variëren, het is gebruikelijk om te gebruiken:
#!/usr/bin/env perl
in plaats van te proberen te raden of het zo is
/bin/perl, /usr/bin/perl, /usr/local/bin/perl, /usr/local/pkg/perl,
/fileserver/usr/bin/perl, of /home/MrDaniel/usr/bin/perl op de
systeem…Aan de andere kant staat env bijna altijd in /usr/bin/env. (Behalve in
gevallen waarin dat niet het geval is; sommige systemen kunnen /bin/env gebruiken, maar dat is een
vrij zeldzame gelegenheid en gebeurt alleen op niet-Linux-systemen.)
Antwoord 5, autoriteit 5%
De exec
systeemaanroep van de Linux-kernel begrijpt shebangs (#!
) native
Als je bash doet:
./something
op Linux roept dit de systeemaanroep exec
aan met het pad ./something
.
Deze regel van de kernel wordt aangeroepen in het bestand dat is doorgegeven aan exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Het leest de allereerste bytes van het bestand en vergelijkt ze met #!
.
Als de vergelijking waar is, wordt de rest van de regel geparseerd door de Linux-kernel, die een andere exec
-aanroep doet met:
- uitvoerbaar:
/usr/bin/env
- eerste argument:
python
- tweede argument: scriptpad
dus gelijk aan:
/usr/bin/env python /path/to/script.py
env
is een uitvoerbaar bestand dat PATH
zoekt om b.v. zoek /usr/bin/python
en roept ten slotte:
/usr/bin/python /path/to/script.py
De Python-interpreter ziet de regel #!
in het bestand, maar #
is het commentaarteken in Python, dus die regel wordt gewoon genegeerd als een gewone opmerking.
En ja, je kunt een oneindige lus maken met:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
bash herkent de fout:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
is toevallig menselijk leesbaar, maar dat is niet vereist.
Als het bestand met verschillende bytes is gestart, zou de exec
Systeemoproep een andere handler gebruiken. De andere belangrijkste ingebouwde handler is voor ELF-uitvoerbare bestanden: HTTPS://github.com/torValds/LINUX/BOB/V4.8/FS/BINFMT_ELF.C#L1305 welke controleert op bytes 7f 45 4c 46
(die ook gebeurt om menselijk leesbaar te zijn voor .ELF
). Laten we bevestigen dat door de 4 eerste bytes van /bin/ls
, een ELF-uitvoerbaar bestand is:
head -c 4 "$(which ls)" | hd
Uitgang:
00000000 7f 45 4c 46 |.ELF|
00000004
Dus wanneer de kernel die bytes ziet, neemt het het ELF-bestand in, plaatst deze correct in het geheugen en begint er een nieuw proces mee. Zie ook: Hoe is kernel Ontvang een uitvoerbaar binair bestand dat onder Linux wordt uitgevoerd?
Ten slotte kunt u uw eigen Shebang-handlers toevoegen met de binfmt_misc
mechanisme. U kunt bijvoorbeeld een aangepaste handler voor .jar
Bestanden . Dit mechanisme ondersteunt zelfs handlers per bestandsextensie. Een andere applicatie is bij transparant uitvoeren van executables van een andere architectuur met Qemu .
Ik denk niet posix Specificeert Shebangs echter : https://unix.stackexchange.com/a/346214/32558 , hoewel het vermeldt in Rationale Secties, en in het formulier “als uitvoerbare scripts worden ondersteund door het systeem dat er iets kan gebeuren”. MacOS en FreeBSD lijken echter ook te implementeren.
PATH
Zoek motivatie
Waarschijnlijk is een grote motivatie voor het bestaan van Shebangs het feit dat we in Linux vaak opdrachten willen uitvoeren van PATH
net als:
basename-of-command
In plaats van:
/full/path/to/basename-of-command
Maar dan, zonder het Shebang-mechanisme, hoe zou Linux weten hoe u elk type bestand kunt starten?
Hardcoding De extensie in opdrachten:
basename-of-command.py
of implementatiepad zoeken op elke tolk:
python basename-of-command
zou een mogelijkheid zijn, maar dit heeft het grote probleem dat alles kapot gaat als we ooit besluiten om het commando in een andere taal te refactoreren.
Kepers lossen dit probleem prachtig op.
Belangrijk gebruik van env
: pyenv
en andere versiebeheerders
Een belangrijk gebruiksvoorbeeld van waarom u #!/usr/bin/env python
zou moeten gebruiken in plaats van alleen /usr/bin/python
is dat van versiebeheerders met pyenv
.
Met
pyenv
kunt u eenvoudig meerdere python-versies op één machine installeren, zodat u andere projecten beter kunt reproduceren zonder virtualisatie.
Vervolgens beheert het de “huidige” pythonversie door de volgorde in het PATH in te stellen: b.v. zoals getoond op apt-get install voor verschillende python-versieseen door pyenv beheerde python kan zich bevinden op:
/home/ciro/.pyenv/shims/python
dus nergens in de buurt van /usr/bin/python
, waarmee sommige systemen kunnen omgaan via update-alternatives
symbolische links.
Antwoord 6, autoriteit 4%
Misschien is uw vraag in deze zin:
Als je het volgende wilt gebruiken: $python myscript.py
Je hebt die regel helemaal niet nodig. Het systeem roept python aan en vervolgens zal de python-interpreter je script uitvoeren.
Maar als u van plan bent het volgende te gebruiken: $./myscript.py
Roept u rechtstreeks als een normaal programma of een bash-script, u hoeft die regel te schrijven om op te geven aan het systeem dat het programma gebruikt om het uit te voeren (en maakt het ook uitvoerbaar bestand met chmod 755
)
7, Autoriteit 3%
Technisch gezien, in Python, dit is slechts een reactie-lijn.
Deze regel wordt alleen gebruikt als u het PY-script van de Shell (van de opdrachtregel) uitvoert. Dit is bekend als de “shebang !” , en Het wordt in verschillende situaties gebruikt, niet alleen met Python-scripts.
Hier geeft het de schaal op om een specifieke versie van Python te starten (om voor de rest van het bestand te zorgen.
8, Autoriteit 3%
De belangrijkste reden om dit te doen is om het script draagbaar te maken over het besturingssysteemomgevingen.
Bijvoorbeeld onder MingW, Python-scripts gebruiken:
#!/c/python3k/python
en onder GNU / Linux-distributie is het:
#!/usr/local/bin/python
of
#!/usr/bin/python
en onder het beste commerciële Unix SW / HW-systeem van alle (OS / X), is het:
#!/Applications/MacPython 2.5/python
of op FreeBSD:
#!/usr/local/bin/python
Maar al deze verschillen kunnen het script draagbaar maken door gebruik te maken van:
#!/usr/bin/env python
9, Autoriteit 2%
Het is waarschijnlijk logisch om één ding te benadrukken dat de meesten hebben gemist, wat onmiddellijk begrip in de weg kan staan. Wanneer u python
typt in terminal, geeft u normaal gesproken geen volledig pad op. In plaats daarvan wordt het uitvoerbare bestand opgezocht in de omgevingsvariabele PATH
. Als je op zijn beurt een Python-programma rechtstreeks wilt uitvoeren, /path/to/app.py
, moet je de shell vertellen welke interpreter moet worden gebruikt (via de hashbang, wat de andere bijdragers hierboven uitleggen).
Hashbang verwacht het volledige padnaar een tolk. Dus om je Python-programma rechtstreeks uit te voeren, moet je het volledige pad naar het binaire bestand van Python opgeven, wat aanzienlijk varieert, vooral gezien het gebruik van virtualenv. Om portabiliteit aan te pakken wordt de truc met /usr/bin/env
gebruikt. De laatste is oorspronkelijk bedoeld om de omgeving ter plaatse te wijzigen en er een opdracht in uit te voeren. Als er geen wijziging wordt aangebracht, voert het de opdracht uit in de huidige omgeving, wat in feite resulteert in dezelfde PATH
-zoekopdracht die de truc doet.
Antwoord 10
Dit is een shell-conventie die de shell vertelt welk programma het script kan uitvoeren.
#!/usr/bin/env python
wordt opgelost in een pad naar het binaire bestand van Python.
Antwoord 11
Het is de aanbevolen manier, voorgesteld in de documentatie:
2.2.2. Uitvoerbare Python-scripts
Op BSD-achtige Unix-systemen kunnen Python-scripts direct worden gemaakt
uitvoerbaar, zoals shellscripts, door de regel te plaatsen#! /usr/bin/env python3.2
van http://docs.python.org/py3k /tutorial/interpreter.html#executable-python-scripts
Antwoord 12
U kunt dit probleem proberen met virtualenv
Hier is test.py
#! /usr/bin/env python
import sys
print(sys.version)
Virtuele omgevingen maken
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
activeer elke omgeving en controleer de verschillen
echo $PATH
./test.py
Antwoord 13
Het geeft alleen aan welke interpreter u wilt gebruiken. Om dit te begrijpen, maakt u een bestand via terminal door touch test.py
te doen en typt u vervolgens het volgende in dat bestand:
#!/usr/bin/env python3
print "test"
en doe chmod +x test.py
om je script uitvoerbaar te maken. Hierna, wanneer u ./test.py
doet, zou u een foutmelding moeten krijgen met de tekst:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
omdat python3 de printoperator niet ondersteunt.
Ga je gang en verander de eerste regel van je code in:
#!/usr/bin/env python2
en het zal werken door test
af te drukken naar stdout, omdat python2 de printoperator ondersteunt. Dus nu heb je geleerd hoe je kunt schakelen tussen scriptinterpreters.
Antwoord 14
Het lijkt mij alsof de bestanden hetzelfde werken zonder die regel.
Zo ja, gebruik je dan misschien het Python-programma op Windows? Windows gebruikt die regel niet, maar gebruikt de bestandsnaamextensie om het programma uit te voeren dat aan de bestandsextensie is gekoppeld.
Echterin 2011 een “Python launcher”is ontwikkeld die (tot op zekere hoogte) dit Linux-gedrag voor Windows nabootst. Dit is beperkt tot het kiezen welke Python-interpreter wordt uitgevoerd – b.v. om te kiezen tussen Python 2 en Python 3 op een systeem waarop beide zijn geïnstalleerd. Het opstartprogramma wordt optioneel geïnstalleerd als py.exe
door Python-installatie en kan worden gekoppeld aan .py
-bestanden, zodat het opstartprogramma die regel controleert en op zijn beurt de opgegeven Python start tolkversie.
Antwoord 15
Dit is meer historische informatie dan een ‘echt’ antwoord.
Onthoud dat je vroeger VEEL Unix-achtige besturingssystemen had waarvan de ontwerpers allemaal hun eigen idee hadden van waar ze dingen moesten plaatsen, en die soms geen Python, Perl, Bash of tal van andere GNU/Open Source bevatten dingen helemaal.
Dit gold zelfs voor verschillende Linux-distributies. Op Linux–pre-FHS[1]- heb je misschien python in /usr/bin/ of /usr/local/bin/. Of het is misschien niet geïnstalleerd, dus je hebt het zelf gebouwd en in ~/bin
. geplaatst
Solaris was de slechtste waaraan ik ooit heb gewerkt, deels als de overgang van Berkeley Unix naar System V. Je zou kunnen eindigen met dingen in /usr/, /usr/local/, /usr/ucb, /opt/ etc. Dit kan voor sommige echtlange paden zorgen. Ik heb herinneringen aan de dingen van Sunfreeware.com die elk pakket in zijn eigen map installeerde, maar ik kan me niet herinneren of het de binaire bestanden in /usr/bin symlinkte of niet.
O, en soms stond /usr/bin op een NFS-server[2].
Dus het hulpprogramma env
is ontwikkeld om dit te omzeilen.
Dan zou je #!/bin/env interpreter
kunnen schrijven en zolang het pad juist was, hadden de dingen een redelijkekans om te werken. Natuurlijk betekende redelijk(voor Python en Perl) dat je ook de juiste omgevingsvariabelen had ingesteld. Voor bash/ksh/zsh werkte het gewoon.
Dit was belangrijk omdat mensen shellscripts doorgaven (zoals perl en python) en als je /usr/bin/python hard had gecodeerd op je Red Hat Linux-werkstation, zou het kapot gaan op een SGI… nou nee, ik denk dat IRIX python op de juiste plek heeft gezet. Maar op een Sparc-station werkt het misschien helemaal niet.
Ik mis mijn sparc-station. Maar niet veel. Ok, nu heb je me aan het trollen op E-Bay. Basten.
[1] Hiërarchiestandaard voor bestandssysteem. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Ja, en soms doen mensen dat soort dingen nog steeds. En nee, ik droeg geen raap OF ui aan mijn riem.
16
De regel #!/bin/bash/python3
of #!/bin/bash/python
Geeft aan welke Python Compiler te gebruiken is. Mogelijk hebt u meerdere Python-versies geïnstalleerd. Bijvoorbeeld
a.py:
#!/bin/bash/python3
print("Hello World")
is een python3-script en
b.py:
#!/bin/bash/python
print "Hello World"
is een Python 2.x-script
Om dit bestand te gebruiken ./a.py
of ./b.py
WORDT GEBRUIKT, MOET U DE PRESTATIES VOOR DE BESTANDIGHEDEN VOOR DE PRIVECTIE Geeft, anders zal het uitvoeren van Permission denied
fout.
Voor het geven van uitvoeringstoestemming,
chmod +x a.py
17
Gezien de draagbaarheidskwesties tussen python2
en python3
, moet u altijd van beide versie opgeven, tenzij uw programma compatibel is met beide.
Sommige distributies zijn verzending python
Symlinked to python3
Al een tijdje – Vertrouw nu niet op python
Zien python2
.
Dit wordt benadrukt door pep 394 :
Om verschillen over platforms te tolereren, alle nieuwe code die
moet de python-interpreter oproepen, mag geen python opgeven, maar
eerder zou Python2 of Python3 (of des te specifieker moeten worden opgegeven
Python2.x en Python3.x-versies; Zie de migratie notities ). Dit
Onderscheid moet worden gemaakt in Shebangs, bij het aanroepen van een schaal
Script, bij het aanroepen van via het oproep van het systeem () of bij het aanroepen van in elke
andere context.
18
Het vertelt de tolk welke versie van Python het programma kan uitvoeren wanneer u meerdere versies van Python hebt.
19
Hiermee kunt u het uitvoerbare bestand selecteren dat u wilt gebruiken; wat erg is
Handig als je misschien meerdere Python-installaties hebt, en verschillende modules
in elk en willen kiezen. b.g
#!/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())
Antwoord 20
dit vertelt het script waar de python-map zich bevindt!
#! /usr/bin/env python