Mi sembra che i file funzionino allo stesso modo senza quella linea.
Mi sembra che i file funzionino allo stesso modo senza quella linea.
Risposte:
Se hai installato diverse versioni di Python, /usr/bin/env
assicurati che l'interprete utilizzato sia il primo nel tuo ambiente $PATH
. L'alternativa sarebbe codificare qualcosa del genere #!/usr/bin/python
; va bene, ma meno flessibile.
In Unix, un file eseguibile che deve essere interpretato può indicare quale interprete utilizzare avendo un #!
all'inizio della prima riga, seguito dall'interprete (e da eventuali flag di cui potrebbe aver bisogno).
Se stai parlando di altre piattaforme, ovviamente, questa regola non si applica (ma quella "linea shebang" non fa male e ti aiuterà se copi mai quello script su una piattaforma con una base Unix, come Linux, Mac , eccetera).
chmod +x myscript.py
) e quindi eseguendolo direttamente:, ./myscript.py
piuttosto che solo python myscript.py
.
env
offre la massima flessibilità in quanto l'utente può selezionare l'interprete da utilizzare modificando il PERCORSO. Spesso questa flessibilità non è richiesta e il rovescio della medaglia è che Linux, ad esempio, non può usare il nome dello script per il nome del processo in ps
e ripristina "python". Ad esempio, nel confezionare app Python per distribuzioni, consiglio di non utilizzarle env
.
py
launcher può usare la linea shebang su Windows. È incluso in Python 3.3 o può essere installato in modo indipendente .
/usr/bin/env: Key has expired
dopo molte ore.
Questa si chiama la linea Shebang . Come spiega la voce di Wikipedia :
Nell'informatica, uno shebang (chiamato anche hashbang, hashpling, pound bang o crunchbang) si riferisce ai caratteri "#!" quando sono i primi due caratteri in una direttiva interprete come prima riga di un file di testo. In un sistema operativo simile a Unix, il programma di caricamento programma prende la presenza di questi due caratteri come indicazione che il file è uno script e tenta di eseguire quello script utilizzando l'interprete specificato dal resto della prima riga nel file.
Vedi anche la voce Domande frequenti su Unix .
Anche su Windows, dove la linea shebang non determina l'interprete da eseguire, è possibile passare le opzioni all'interprete specificandole sulla linea shebang. Trovo utile mantenere una linea shebang generica in script una tantum (come quelli che scrivo quando rispondo a domande su SO), quindi posso testarli rapidamente su Windows e ArchLinux .
L' utility env ti consente di invocare un comando sul percorso:
Il primo argomento rimanente specifica il nome del programma da richiamare; viene cercato in base alla
PATH
variabile di ambiente. Eventuali argomenti rimanenti vengono passati come argomenti a quel programma.
Espandendo un po 'le altre risposte, ecco un piccolo esempio di come i tuoi script da riga di comando possono mettersi nei guai con un uso incauto delle /usr/bin/env
linee shebang:
$ /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
Il modulo json non esiste in Python 2.5.
Un modo per evitare questo tipo di problema è utilizzare i nomi dei comandi python con versione che sono generalmente installati con la maggior parte dei Python:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Se devi solo distinguere tra Python 2.xe Python 3.x, anche le versioni recenti di Python 3 forniscono un python3
nome:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
ritorna /usr/bin/python
, un percorso di directory locale potrebbe essere difficile codificato: #!/usr/bin/python
. Ma questo è meno flessibile di quello #!/usr/bin/env python
che ha un'applicazione globale.
Per eseguire lo script Python, dobbiamo dire alla shell tre cose:
Lo shebang #!
compie (1.). Lo shebang inizia con un #
perché il #
personaggio è un marcatore di commento in molti linguaggi di scripting. Il contenuto della linea shebang viene quindi automaticamente ignorato dall'interprete.
Il env
comando esegue (2.) e (3.). Per citare "grawity",
Un uso comune del
env
comando è quello di avviare gli interpreti, sfruttando il fatto che env cercherà $ PATH per il comando che gli viene detto di lanciare. Poiché la linea shebang richiede un percorso assoluto da specificare e poiché la posizione di vari interpreti (perl, bash, python) può variare molto, è comune usare:
#!/usr/bin/env perl
invece di provare a indovinare se si tratta di / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl o / home / MrDaniel / usr / bin / perl sul sistema dell'utente ...D'altra parte, env è quasi sempre in / usr / bin / env. (Tranne nei casi in cui non lo è; alcuni sistemi potrebbero utilizzare / bin / env, ma questa è un'occasione abbastanza rara e si verifica solo su sistemi non Linux.)
Forse la tua domanda è in questo senso:
Se vuoi usare: $python myscript.py
Non hai affatto bisogno di quella linea. Il sistema chiamerà python e quindi l'interprete python eseguirà il tuo script.
Ma se hai intenzione di usare: $./myscript.py
Chiamandolo direttamente come un normale programma o script bash, è necessario scrivere quella riga per specificare al sistema quale programma utilizzare per eseguirlo (e anche renderlo eseguibile con chmod 755
)
La exec
chiamata di sistema del kernel Linux comprende #!
nativamente shebangs ( )
Quando fai su bash:
./something
su Linux, questo chiama la exec
chiamata di sistema con il percorso ./something
.
Questa riga del kernel viene chiamata sul file passato a exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Legge i primi byte del file e li confronta con #!
.
Se il confronto è vero, il resto della riga viene analizzato dal kernel Linux, che effettua un'altra exec
chiamata con percorso /usr/bin/env python
e file corrente come primo argomento:
/usr/bin/env python /path/to/script.py
e questo funziona con qualsiasi linguaggio di scripting che utilizza #
come carattere di commento.
E sì, puoi fare un ciclo infinito con:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash riconosce l'errore:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
sembra essere leggibile dall'uomo, ma non è necessario.
Se il file si avviava con byte diversi, la exec
chiamata di sistema utilizzava un gestore diverso. L'altro gestore incorporato più importante è per i file eseguibili ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 che verifica la presenza di byte 7f 45 4c 46
(che risulta essere umano leggibile per .ELF
). Confermiamo leggendo i primi 4 byte di /bin/ls
, che è un eseguibile ELF:
head -c 4 "$(which ls)" | hd
produzione:
00000000 7f 45 4c 46 |.ELF|
00000004
Quindi quando il kernel vede quei byte, prende il file ELF, lo mette in memoria correttamente e avvia un nuovo processo con esso. Vedi anche: In che modo il kernel ottiene un file binario eseguibile in esecuzione su Linux?
Infine, puoi aggiungere i tuoi gestori shebang con il binfmt_misc
meccanismo. Ad esempio, è possibile aggiungere un gestore personalizzato per i .jar
file . Questo meccanismo supporta anche i gestori per estensione del file. Un'altra applicazione è eseguire in modo trasparente eseguibili di un'architettura diversa con QEMU .
Tuttavia , non credo che POSIX specifichi shebang: https://unix.stackexchange.com/a/346214/32558 , anche se menzionato nelle sezioni logiche e nel modulo "se gli script eseguibili sono supportati dal sistema qualcosa potrebbe accadere". macOS e FreeBSD sembrano comunque implementarlo.
PATH
cerca la motivazione
Probabilmente, una grande motivazione per l'esistenza di shebangs è il fatto che in Linux, spesso vogliamo eseguire comandi PATH
proprio come:
basename-of-command
invece di:
/full/path/to/basename-of-command
Ma poi, senza il meccanismo shebang, come farebbe Linux a sapere come avviare ogni tipo di file?
Hardcoding dell'estensione nei comandi:
basename-of-command.py
o implementando la ricerca PATH su ogni interprete:
python basename-of-command
sarebbe una possibilità, ma questo ha il problema maggiore che tutto si rompe se decidessimo mai di rifattare il comando in un'altra lingua.
Shebangs risolve questo problema magnificamente.
Tecnicamente, in Python, questa è solo una riga di commento.
Questa riga viene utilizzata solo se si esegue lo script py dalla shell (dalla riga di comando). Questo è noto come " Shebang !" e viene utilizzato in varie situazioni, non solo con gli script Python.
Qui, indica alla shell di avviare una versione specifica di Python (per occuparsi del resto del file.
py.exe
. Questo fa parte di un'installazione standard di Python.
Il motivo principale per farlo è rendere lo script portatile in tutti gli ambienti del sistema operativo.
Ad esempio in mingw, gli script python usano:
#!/c/python3k/python
e sotto distribuzione GNU / Linux è:
#!/usr/local/bin/python
o
#!/usr/bin/python
e sotto il miglior sistema commerciale Unix sw / hw di tutti (OS / X), è:
#!/Applications/MacPython 2.5/python
o su FreeBSD:
#!/usr/local/bin/python
Tuttavia, tutte queste differenze possono rendere lo script portatile in tutto usando:
#!/usr/bin/env python
/usr/bin/python
. Sotto Linux, anche il Python installato dal sistema è quasi certamente /usr/bin/python
(non ho mai visto nient'altro e non avrebbe senso). Nota che potrebbero esserci sistemi che non hanno /usr/bin/env
.
python
non è portatile, è interprete Python predefinito di distribuzione. Arch Linux utilizza Python 3 per impostazione predefinita per molto tempo e potrebbero anche pensarci le distribuzioni perché Python 2 è supportato solo fino al 2020.
Probabilmente ha senso enfatizzare una cosa che la maggior parte ha perso, che può impedire una comprensione immediata. Quando si digita il python
terminale normalmente non si fornisce un percorso completo. Al contrario, l'eseguibile viene cercato nella PATH
variabile d'ambiente. A sua volta, quando si desidera eseguire direttamente un programma Python /path/to/app.py
, si deve dire alla shell quale interprete usare (tramite l' hashbang , cosa spiegano gli altri contributori sopra).
Hashbang prevede il percorso completo per un interprete. Pertanto, per eseguire direttamente il tuo programma Python devi fornire un percorso completo al binario Python che varia in modo significativo, specialmente considerando l'uso di virtualenv . Per affrontare la portabilità /usr/bin/env
viene utilizzato il trucco . Quest'ultimo è originariamente destinato a modificare l'ambiente sul posto ed eseguire un comando al suo interno. Quando non viene fornita alcuna modifica, viene eseguito il comando nell'ambiente corrente, il che si traduce effettivamente nella stessa PATH
ricerca che fa il trucco.
Questa è una convenzione della shell che dice alla shell quale programma può eseguire lo script.
#! / usr / bin / env python
si risolve in un percorso del binario Python.
È consigliato, proposto nella documentazione:
2.2.2. Script Python eseguibili
Sui sistemi Unix BSD, gli script Python possono essere resi direttamente eseguibili, come gli script shell, inserendo la linea
#! /usr/bin/env python3.2
da http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Puoi provare questo problema usando virtualenv
Ecco test.py
#! /usr/bin/env python
import sys
print(sys.version)
Crea ambienti virtuali
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
attiva ogni ambiente quindi controlla le differenze
echo $PATH
./test.py
Specifica solo quale interprete si desidera utilizzare. Per capirlo, crea un file attraverso il terminale facendo touch test.py
, quindi digita in quel file quanto segue:
#!/usr/bin/env python3
print "test"
e fai chmod +x test.py
per rendere eseguibile il tuo script. Dopo questo quando lo fai ./test.py
dovresti ricevere un errore che dice:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
perché python3 non supporta l'operatore di stampa.
Ora vai avanti e modifica la prima riga del codice in:
#!/usr/bin/env python2
e funzionerà, stampando test
su stdout, perché python2 supporta l'operatore di stampa. Quindi, ora hai imparato a passare da un interprete di script all'altro.
Mi sembra che i file funzionino allo stesso modo senza quella linea.
Se è così, forse stai eseguendo il programma Python su Windows? Windows non utilizza quella linea, ma utilizza l'estensione del nome file per eseguire il programma associato all'estensione del file.
Tuttavia, nel 2011, è stato sviluppato un "launcher Python" che (in una certa misura) imita questo comportamento di Linux per Windows. Ciò si limita solo alla scelta dell'interprete Python da eseguire, ad esempio per selezionare tra Python 2 e Python 3 su un sistema in cui entrambi sono installati. Il programma di avvio è facoltativamente installato come py.exe
dall'installazione di Python e può essere associato ai .py
file in modo che il programma di avvio controllerà quella linea e, a sua volta, avvierà la versione dell'interprete Python specificata.
$ python myscript.py
.
Questo significa più informazioni storiche che una risposta "reale".
Ricorda che nel passato avevi MOLTO sistemi unix come i sistemi operativi i cui progettisti avevano tutti la propria idea di dove mettere le cose, e a volte non includevano Python, Perl, Bash o molte altre cose GNU / Open Source affatto .
Questo era vero anche per le diverse distribuzioni Linux. Su Linux - pre-FHS [1] - potresti avere Python in / usr / bin / o / usr / local / bin /. Oppure potrebbe non essere stato installato, quindi hai creato il tuo e lo hai inserito in ~ / bin
Solaris è stato il peggiore su cui abbia mai lavorato, in parte come il passaggio da Berkeley Unix a System V. Potresti finire con le cose in / usr /, / usr / local /, / usr / ucb, / opt / ecc. Questo potrebbe rendere per alcuni percorsi davvero lunghi. Ho ricordi delle cose di Sunfreeware.com che installavano ciascun pacchetto nella sua directory, ma non ricordo se collegasse i binari in / usr / bin o meno.
Oh, e talvolta / usr / bin era su un server NFS [2].
Quindi l' env
utilità è stata sviluppata per aggirare questo problema.
Quindi potresti scrivere #!/bin/env interpreter
e fintanto che il percorso era corretto le cose avevano una ragionevole possibilità di correre. Naturalmente, ragionevole significava (per Python e Perl) che avevate anche impostato le variabili ambientali appropriate. Per bash / ksh / zsh ha funzionato.
Questo era importante perché le persone passavano per gli script di shell (come perl e python) e se avessi hard coded / usr / bin / python sulla tua stazione di lavoro Red Hat Linux si sarebbe rotto male su un SGI ... beh, no , Penso che IRIX abbia messo Python nel posto giusto. Ma su una stazione Sparc potrebbe non funzionare affatto.
Mi manca la mia stazione sparc. Ma non molto. Ok, ora mi fai andare a pesca a traina su E-Bay. Bastages.
[1] Standard della gerarchia del file system. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Sì, e talvolta le persone fanno ancora cose del genere. E no, non indossavo né una rapa né una cipolla sulla cintura.
Se stai eseguendo il tuo script in un ambiente virtuale, ad esempio venv
, eseguendolo which python
mentre lavori venv
visualizzerà il percorso dell'interprete Python:
~/Envs/venv/bin/python
Si noti che il nome dell'ambiente virtuale è incorporato nel percorso dell'interprete Python. Pertanto, codificare questo percorso nello script causerà due problemi:
Pertanto, per aggiungere alla risposta di Jonathan , lo shebang ideale è #!/usr/bin/env python
non solo per la portabilità su tutti i sistemi operativi, ma anche per la portabilità in ambienti virtuali!
Considerando i problemi di portabilità tra python2
e python3
, è necessario specificare sempre una delle versioni a meno che il programma non sia compatibile con entrambe.
Alcune distribuzioni sono in python
collegamento simbolico da python3
un po 'di tempo - non fare affidamento python
sull'essere python2
.
Ciò è sottolineato da PEP 394 :
Per tollerare le differenze tra le piattaforme, tutto il nuovo codice che deve invocare l'interprete Python non deve specificare python, ma piuttosto specificare python2 o python3 (o le versioni più specifiche di python2.xe python3.x; consultare le Note sulla migrazione ) . Questa distinzione dovrebbe essere fatta in shebang, quando si invoca da uno script di shell, quando si invoca tramite la chiamata di sistema () o quando si invoca in qualsiasi altro contesto.
Ti consente di selezionare l'eseguibile che desideri utilizzare; che è molto utile se forse hai più installazioni di Python e moduli diversi in ognuna e desideri scegliere. per esempio
#!/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())
questo dice allo script dov'è la directory di Python!
#! /usr/bin/env python
#!/usr/bin/env python
in alto.