Me parece que los archivos se ejecutan igual sin esa línea.
Me parece que los archivos se ejecutan igual sin esa línea.
Respuestas:
Si tiene varias versiones de Python instaladas, /usr/bin/env
se asegurará de que el intérprete utilizado sea el primero en el entorno.$PATH
. La alternativa sería codificar algo así #!/usr/bin/python
; está bien, pero menos flexible.
En Unix, un archivo ejecutable que debe interpretarse puede indicar qué intérprete usar al tener un#!
al comienzo de la primera línea, seguido del intérprete (y cualquier indicador que pueda necesitar).
Si habla de otras plataformas, por supuesto, esta regla no se aplica (pero esa "línea shebang" no hace daño y ayudará si alguna vez copia ese script en una plataforma con una base Unix, como Linux, Mac , etc.)
chmod +x myscript.py
) y luego ejecutándolo directamente: en ./myscript.py
lugar de solo python myscript.py
.
env
proporciona la máxima flexibilidad, ya que el usuario puede seleccionar el intérprete para usar cambiando la RUTA. Sin embargo, a menudo esta flexibilidad no es necesaria y la desventaja es que Linux, por ejemplo, no puede usar el nombre del script para el nombre del proceso ps
y vuelve a "python". Al empaquetar aplicaciones de Python para distribuciones, por ejemplo, recomendaría no usar env
.
py
El lanzador puede usar la línea shebang en Windows. Se incluye en Python 3.3 o se puede instalar de forma independiente .
/usr/bin/env: Key has expired
después de muchas horas.
Eso se llama la línea shebang . Como explica la entrada de Wikipedia :
En informática, un shebang (también llamado hashbang, hashpling, pound bang o crunchbang) se refiere a los caracteres "#!" cuando son los dos primeros caracteres en una directiva de intérprete como la primera línea de un archivo de texto. En un sistema operativo tipo Unix, el cargador de programas toma la presencia de estos dos caracteres como una indicación de que el archivo es un script e intenta ejecutar ese script utilizando el intérprete especificado por el resto de la primera línea del archivo.
Consulte también la entrada de Preguntas frecuentes de Unix .
Incluso en Windows, donde la línea shebang no determina el intérprete que se ejecutará, puede pasar opciones al intérprete al especificarlas en la línea shebang. Me resulta útil mantener una línea shebang genérica en scripts únicos (como los que escribo al responder preguntas en SO), para poder probarlos rápidamente en Windows y ArchLinux .
La utilidad env le permite invocar un comando en la ruta:
El primer argumento restante especifica el nombre del programa a invocar; se busca según la
PATH
variable de entorno. Cualquier argumento restante se pasa como argumento a ese programa.
Ampliando un poco las otras respuestas, aquí hay un pequeño ejemplo de cómo sus scripts de línea de comando pueden meterse en problemas por el uso incauto de las /usr/bin/env
líneas 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
El módulo json no existe en Python 2.5.
Una forma de protegerse contra ese tipo de problema es usar los nombres de comandos de Python versionados que normalmente se instalan con la mayoría de las Pythons:
$ cat my_script.py
#!/usr/bin/env python2.6
import json
print "hello, json"
Si solo necesita distinguir entre Python 2.xy Python 3.x, las versiones recientes de Python 3 también proporcionan un python3
nombre:
$ cat my_script.py
#!/usr/bin/env python3
import json
print("hello, json")
which python
vuelve /usr/bin/python
, una ruta de directorio local podría estar codificado: #!/usr/bin/python
. Pero eso es menos flexible que el #!/usr/bin/env python
que tiene una aplicación global.
Para ejecutar el script de Python, necesitamos decirle al shell tres cosas:
El shebang #!
cumple (1.). El shebang comienza con un #
porque el #
personaje es un marcador de comentario en muchos lenguajes de secuencias de comandos. Por lo tanto, el intérprete ignora automáticamente el contenido de la línea shebang.
El env
comando cumple (2.) y (3.). Para citar "gravedad",
Un uso común del
env
comando es lanzar intérpretes, haciendo uso del hecho de que env buscará en $ PATH el comando que se le indica que inicie. Dado que la línea shebang requiere que se especifique una ruta absoluta y que la ubicación de varios intérpretes (perl, bash, python) puede variar mucho, es común usar:
#!/usr/bin/env perl
en lugar de tratar de adivinar si es / bin / perl, / usr / bin / perl, / usr / local / bin / perl, / usr / local / pkg / perl, / fileserver / usr / bin / perl, o / home / MrDaniel / usr / bin / perl en el sistema del usuario ...Por otro lado, env casi siempre está en / usr / bin / env. (Excepto en los casos en que no lo es; algunos sistemas pueden usar / bin / env, pero esa es una ocasión bastante rara y solo ocurre en sistemas que no son Linux).
Quizás su pregunta es en este sentido:
Si quieres usar: $python myscript.py
No necesitas esa línea en absoluto. El sistema llamará a python y luego el intérprete de python ejecutará su script.
Pero si tiene la intención de usar: $./myscript.py
Al llamarlo directamente como un programa normal o un script bash, debe escribir esa línea para especificar al sistema qué programa usar para ejecutarlo (y también hacer que sea ejecutable con chmod 755
)
La exec
llamada al sistema del kernel de Linux comprende shebangs ( #!
) de forma nativa
Cuando lo haces en bash:
./something
en Linux, esto llama a la exec
llamada del sistema con la ruta ./something
.
Esta línea del núcleo se llama en el archivo pasado a exec
: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25
if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))
Lee los primeros bytes del archivo y los compara con #!
.
Si la comparación es verdadera, el núcleo de Linux analiza el resto de la línea, que realiza otra exec
llamada con la ruta /usr/bin/env python
y el archivo actual como primer argumento:
/usr/bin/env python /path/to/script.py
y esto funciona para cualquier lenguaje de secuencias de comandos que se use #
como carácter de comentario.
Y sí, puedes hacer un ciclo infinito con:
printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a
Bash reconoce el error:
-bash: /a: /a: bad interpreter: Too many levels of symbolic links
#!
Simplemente resulta ser legible para los humanos, pero eso no es obligatorio.
Si el archivo comenzó con diferentes bytes, la exec
llamada al sistema usaría un controlador diferente. El otro controlador incorporado más importante es para archivos ejecutables ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 que comprueba los bytes 7f 45 4c 46
(que también son humanos legible para .ELF
). Confirmemos eso leyendo los 4 primeros bytes de /bin/ls
, que es un ejecutable ELF:
head -c 4 "$(which ls)" | hd
salida:
00000000 7f 45 4c 46 |.ELF|
00000004
Entonces, cuando el kernel ve esos bytes, toma el archivo ELF, lo guarda en la memoria correctamente y comienza un nuevo proceso con él. Ver también: ¿Cómo obtiene el núcleo un archivo binario ejecutable que se ejecuta en Linux?
Finalmente, puede agregar sus propios manejadores de shebang con el binfmt_misc
mecanismo. Por ejemplo, puede agregar un controlador personalizado para .jar
archivos . Este mecanismo incluso admite controladores por extensión de archivo. Otra aplicación es ejecutar de forma transparente ejecutables de una arquitectura diferente con QEMU .
Sin embargo , no creo que POSIX especifique shebangs: https://unix.stackexchange.com/a/346214/32558 , aunque sí menciona en las secciones de justificación, y en la forma "si el sistema admite scripts ejecutables, algo puede suceder". macOS y FreeBSD también parecen implementarlo sin embargo.
PATH
buscar motivación
Probablemente, una gran motivación para la existencia de shebangs es el hecho de que en Linux, a menudo queremos ejecutar comandos desde PATH
:
basename-of-command
en vez de:
/full/path/to/basename-of-command
Pero entonces, sin el mecanismo shebang, ¿cómo sabría Linux cómo iniciar cada tipo de archivo?
Codificar la extensión en comandos:
basename-of-command.py
o implementar la búsqueda PATH en cada intérprete:
python basename-of-command
sería una posibilidad, pero este tiene el principal problema de que todo se rompe si alguna vez decidimos refactorizar el comando a otro idioma.
Los shebangs resuelven este problema maravillosamente.
Técnicamente, en Python, esto es solo una línea de comentarios.
Esta línea solo se usa si ejecuta el script py desde el shell (desde la línea de comando). Esto se conoce como el " Shebang !" , y se usa en varias situaciones, no solo con scripts de Python.
Aquí, le indica al shell que inicie una versión específica de Python (para encargarse del resto del archivo.
py.exe
. Esto es parte de una instalación estándar de Python.
La razón principal para hacer esto es hacer que el script sea portátil en todos los entornos del sistema operativo.
Por ejemplo, bajo mingw, los scripts de python usan:
#!/c/python3k/python
y bajo distribución GNU / Linux es:
#!/usr/local/bin/python
o
#!/usr/bin/python
y bajo el mejor sistema comercial Unix sw / hw de todos (OS / X), es:
#!/Applications/MacPython 2.5/python
o en FreeBSD:
#!/usr/local/bin/python
Sin embargo, todas estas diferencias pueden hacer que el script sea portátil a través de todos al usar:
#!/usr/bin/env python
/usr/bin/python
. Bajo Linux, el Python instalado por el sistema también es casi seguro /usr/bin/python
(nunca he visto nada más y no tendría sentido). Tenga en cuenta que puede haber sistemas que no tienen /usr/bin/env
.
python
no es tan portátil, es el intérprete predeterminado de distribución de Python. Arch Linux por defecto es Python 3 durante mucho tiempo y es posible que las distribuciones también lo piensen porque Python 2 solo es compatible hasta 2020.
Probablemente tenga sentido enfatizar una cosa que la mayoría se ha perdido, lo que puede impedir la comprensión inmediata. Cuando escribe python
en la terminal, normalmente no proporciona una ruta completa. En cambio, el ejecutable se busca en PATH
la variable de entorno. A su vez, cuando desea ejecutar un programa Python directamente, /path/to/app.py
uno debe decirle al intérprete qué intérprete usar (a través del hashbang , lo que los otros contribuyentes están explicando anteriormente).
Hashbang espera el camino completo a un intérprete. Por lo tanto, para ejecutar su programa Python directamente, debe proporcionar la ruta completa al binario de Python que varía significativamente, especialmente considerando el uso de virtualenv . Para abordar la portabilidad /usr/bin/env
se utiliza el truco con . Este último está destinado originalmente a alterar el entorno en el lugar y ejecutar un comando en él. Cuando no se proporciona ninguna alteración, ejecuta el comando en el entorno actual, lo que efectivamente resulta en la misma PATH
búsqueda que hace el truco.
Esta es una convención de shell que le dice al shell qué programa puede ejecutar el script.
#! / usr / bin / env python
resuelve una ruta al binario de Python.
Es la forma recomendada, propuesta en la documentación:
2.2.2. Scripts ejecutables de Python
En los sistemas BSD'ish Unix, los scripts de Python se pueden hacer directamente ejecutables, como los scripts de shell, al poner la línea
#! /usr/bin/env python3.2
de http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts
Puedes probar este problema usando virtualenv
Aquí está test.py
#! /usr/bin/env python
import sys
print(sys.version)
Crea ambientes virtuales
virtualenv test2.6 -p /usr/bin/python2.6
virtualenv test2.7 -p /usr/bin/python2.7
active cada entorno y luego verifique las diferencias
echo $PATH
./test.py
Solo especifica qué intérprete desea utilizar. Para comprender esto, cree un archivo a través de la terminal haciendo touch test.py
, luego escriba en ese archivo lo siguiente:
#!/usr/bin/env python3
print "test"
y haz chmod +x test.py
que tu script sea ejecutable. Después de esto, cuando lo haga ./test.py
, debería recibir un error que diga:
File "./test.py", line 2
print "test"
^
SyntaxError: Missing parentheses in call to 'print'
porque python3 no admite el operador de impresión.
Ahora continúe y cambie la primera línea de su código a:
#!/usr/bin/env python2
y funcionará, imprimiendo test
en stdout, porque python2 es compatible con el operador de impresión. Entonces, ahora has aprendido a cambiar entre intérpretes de guiones.
Me parece que los archivos se ejecutan igual sin esa línea.
Si es así, ¿tal vez estás ejecutando el programa Python en Windows? Windows no usa esa línea; en su lugar, usa la extensión de nombre de archivo para ejecutar el programa asociado con la extensión de archivo.
Sin embargo, en 2011, se desarrolló un "iniciador de Python" que (hasta cierto punto) imita este comportamiento de Linux para Windows. Esto se limita solo a elegir qué intérprete de Python se ejecuta, por ejemplo, para seleccionar entre Python 2 y Python 3 en un sistema donde ambos están instalados. El iniciador se instala opcionalmente como py.exe
mediante la instalación de Python, y puede asociarse con .py
archivos para que el iniciador verifique esa línea y, a su vez, inicie la versión del intérprete de Python especificada.
$ python myscript.py
.
Esto significa más información histórica que una respuesta "real".
Recuerda que en su día que tenían un montón de sistemas operativos tipo UNIX cuyos diseñadores todos tenían su propia idea de dónde colocar las cosas, ya veces no incluía Python, Perl, Bash, o un montón de otros GNU / Open Source cosas en absoluto .
Esto fue incluso cierto para diferentes distribuciones de Linux. En Linux - pre-FHS [1] -puede tener python en / usr / bin / o / usr / local / bin /. O puede que no se haya instalado, por lo que creó el suyo propio y lo colocó en ~ / bin
Solaris fue el peor en el que he trabajado, en parte como la transición de Berkeley Unix al Sistema V. Podría terminar con cosas en / usr /, / usr / local /, / usr / ucb, / opt / etc. Esto podría hacer que por algunos caminos realmente largos. Tengo recuerdos de las cosas de Sunfreeware.com instalando cada paquete en su propio directorio, pero no recuerdo si unía los enlaces binarios a / usr / bin o no.
Ah, y a veces / usr / bin estaba en un servidor NFS [2].
Entonces, la env
utilidad fue desarrollada para solucionar esto.
Entonces podías escribir #!/bin/env interpreter
y mientras el camino fuera correcto, las cosas tenían una posibilidad razonable de correr. Por supuesto, razonable significaba (para Python y Perl) que también había establecido las variables ambientales apropiadas. Para bash / ksh / zsh simplemente funcionó.
Esto era importante porque la gente pasaba por scripts de shell (como perl y python) y si codificabas / usr / bin / python en tu estación de trabajo Red Hat Linux, se rompería mal en un SGI ... bueno, no , Creo que IRIX puso a Python en el lugar correcto. Pero en una estación Sparc podría no funcionar en absoluto.
Echo de menos mi estación de sparc. Pero no mucho. Ok, ahora me tienes dando vueltas en E-Bay. Bastajes
[1] Estándar de jerarquía del sistema de archivos. https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard
[2] Sí, y a veces la gente todavía hace cosas así. Y no, no llevaba ni un nabo ni una cebolla en el cinturón.
Si está ejecutando su script en un entorno virtual, por ejemplo venv
, al ejecutar which python
mientras trabaja, venv
se mostrará la ruta al intérprete de Python:
~/Envs/venv/bin/python
Tenga en cuenta que el nombre del entorno virtual está incrustado en la ruta al intérprete de Python. Por lo tanto, codificar esta ruta en su script causará dos problemas:
Por lo tanto, para agregar a la respuesta de Jonathan , ¡el shebang ideal es #!/usr/bin/env python
, no solo para la portabilidad entre sistemas operativos, sino también para la portabilidad en entornos virtuales!
Teniendo en cuenta los problemas de portabilidad entre python2
y python3
, siempre debe especificar cualquiera de las versiones a menos que su programa sea compatible con ambas.
Algunas distribuciones se envían por python
enlaces simbólicos python3
desde hace un tiempo, no confíes en python
ser python2
.
PEP 394 enfatiza esto :
Para tolerar diferencias entre plataformas, todo el código nuevo que necesita invocar al intérprete de Python no debe especificar python, sino que debe especificar python2 o python3 (o las versiones más específicas de python2.xy python3.x; consulte las Notas de migración ) . Esta distinción debe hacerse en shebangs, cuando se invoca desde un script de shell, cuando se invoca a través de la llamada system (), o cuando se invoca en cualquier otro contexto.
Le permite seleccionar el ejecutable que desea usar; lo cual es muy útil si quizás tiene varias instalaciones de Python y diferentes módulos en cada una y desea elegir. p.ej
#!/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())
¡Esto le dice al script dónde está el directorio de Python!
#! /usr/bin/env python
#!/usr/bin/env python
en la parte superior.