¿Por qué las personas escriben #! / Usr / bin / env python shebang en la primera línea de un script de Python?

Me parece que los archivos se ejecutan igual sin esa línea.

Si tiene varias versiones de Python instaladas, /usr/bin/env se asegurará de que el intérprete utilizado sea el primero en $PATH su entorno. La alternativa sería codificar algo como #!/usr/bin/python ; eso 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 por el intérprete (y cualquier bandera que pueda necesitar).

Por supuesto, si está hablando de otras plataformas, esta regla no se aplica (pero esa “línea de shebang” no hace daño, y lo ayudará si alguna vez copia ese script a una plataforma con una base Unix, como Linux, Mac). , etc).

Eso se llama la línea shebang . Como explica la entrada de Wikipedia :

En computación, un shebang (también llamado hashbang, hashpling, pound bang o crunchbang) se refiere a los caracteres “#!” cuando son los dos primeros caracteres de una directiva de intérprete como la primera línea de un archivo de texto. En un sistema operativo similar a Unix, el cargador de progtwigs 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 rest de la primera línea del archivo.

Vea 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 pasarle opciones al intérprete especificándolas en la línea shebang. Encuentro útil mantener una línea genérica de shebang en scripts únicos (como los que escribo cuando respondo preguntas en SO), por lo que puedo probarlos rápidamente tanto en Windows como en ArchLinux .

La utilidad env te permite invocar un comando en la ruta:

El primer argumento restante especifica el nombre del progtwig a invocar; Se busca según la PATH entorno PATH . Todos los argumentos restantes se pasan como argumentos a ese progtwig.

Ampliando un poco las otras respuestas, aquí hay un pequeño ejemplo de cómo los scripts de línea de comandos pueden meterse en problemas por el uso imprudente de las líneas /usr/bin/env 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  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 los Pythons:

 $ cat my_script.py #!/usr/bin/env python2.6 import json print "hello, json" 

Si solo necesitas distinguir entre Python 2.xy Python 3.x, las versiones recientes de Python 3 también proporcionan un nombre de python3 :

 $ cat my_script.py #!/usr/bin/env python3 import json print("hello, json") 

Para ejecutar el script de Python, necesitamos decirle al shell tres cosas:

  1. Que el archivo es un script.
  2. Qué intérprete queremos ejecutar el script.
  3. El camino de dicho intérprete.

El shebang #! logra (1.). El shebang comienza con un # porque el carácter # es un marcador de comentario en muchos lenguajes de scripting. Por lo tanto, el intérprete ignora automáticamente el contenido de la línea shebang.

El comando env cumple (2.) y (3.). Para citar “grawity”

Un uso común del comando env es lanzar intérpretes, haciendo uso del hecho de que env buscará $ PATH para el comando que se le dice que inicie. Dado que la línea shebang requiere una ruta absoluta para ser especificada, y como la ubicación de varios intérpretes (perl, bash, python) puede variar mucho, es común usar:

#!/usr/bin/env perl lugar de intentar 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 está casi siempre en / usr / bin / env. (Excepto en los casos en que no lo es; algunos sistemas pueden usar / bin / env, pero eso es una ocasión bastante rara y solo ocurre en sistemas que no son Linux).

Quizás tu pregunta sea 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 pretende usar: $./myscript.py

Al llamarlo directamente como un progtwig normal o un script bash, necesita escribir esa línea para especificar en el sistema qué progtwig usa para ejecutarlo (y también hacerlo ejecutable con chmod 755 )

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 (que se encargue del rest del archivo).

La razón principal para hacer esto es hacer que el script sea portátil en los entornos de los sistemas operativos.

Por ejemplo, en mingw, los scripts de Python usan:

 #!/c/python3k/python 

y bajo la distribución de GNU / Linux es:

 #!/usr/local/bin/python 

o

 #!/usr/bin/python 

y bajo el mejor sistema de sw / hw Unix comercial 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 utilizando todos:

 #!/usr/bin/env python 

La llamada al sistema exec del kernel de Linux comprende shebangs ( #! ) De forma nativa

Cuando haces en bash:

 ./something 

en Linux, esto llama a la llamada al sistema exec con la ruta ./something .

Esta línea del núcleo se llama en el archivo que se pasa a exec : https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25

if ((bprm-> buf [0]! = ‘#’) || (bprm-> buf [1]! = ‘!’))

Esto lee los primeros bytes del archivo y los compara con #! .

Si eso es cierto, entonces el rest de la línea es analizado por el kernel de Linux, que realiza otra llamada ejecutiva con path /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 scripting que use # como un carácter de comentario.

Y sí, puedes hacer un bucle 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 necesario.

Si el archivo comenzó con bytes diferentes, entonces la llamada al sistema exec usaría un controlador diferente. El otro controlador incorporado más importante es para los archivos ejecutables de ELF: https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 que verifica los bytes 7f 45 4c 46 (que también pasa a ser humano legible para .ELF ). Esto lee el archivo ELF, lo coloca en la memoria correctamente y comienza un nuevo proceso con él. Ver también: ¿Cómo obtiene el kernel un archivo binario ejecutable ejecutándose en linux?

Finalmente, puede agregar sus propios controladores shebang con el mecanismo binfmt_misc . Por ejemplo, puede agregar un controlador personalizado para los archivos .jar . Este mecanismo incluso soporta manejadores por extensión de archivo. Otra aplicación es ejecutar ejecutables de forma transparente de una architecture diferente con QEMU .

No creo que POSIX especifique shebangs sin embargo: https://unix.stackexchange.com/a/346214/32558 , aunque sí se menciona en las secciones de fundamentos, y en la forma “si los scripts ejecutables son compatibles con el sistema, algo puede ocurrir”. MacOS y FreeBSD también parecen implementarlo sin embargo.

Probablemente tenga sentido enfatizar una cosa que la mayoría ha omitido, lo que puede impedir la comprensión inmediata. Cuando escribe python en el terminal, normalmente no proporciona una ruta completa. En su lugar, el ejecutable se ha buscado en la variable de entorno PATH A su vez, cuando desea ejecutar un progtwig Python directamente, /path/to/app.py , debe decirle al intérprete de comandos qué intérprete debe usar (a través del hashbang , lo que los otros colaboradores explican anteriormente).

Hashbang espera la ruta completa a un intérprete. Por lo tanto, para ejecutar su progtwig Python directamente, debe proporcionar una ruta completa al binario de Python, que varía significativamente, especialmente considerando el uso de virtualenv . Para abordar la portabilidad, se utiliza el truco con /usr/bin/env . Este último está pensado originalmente para 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 búsqueda PATH que hace el truco.

Fuente de unix stackexchange

Se recomienda camino, propuesto en la documentación:

2.2.2. Scripts Python ejecutables

En los sistemas BSD’ish Unix, los scripts de Python se pueden hacer directamente ejecutables, como shell scripts, poniendo la línea

 #! /usr/bin/env python3.2 

de http://docs.python.org/py3k/tutorial/interpreter.html#executable-python-scripts

Esta es una convención de shell que le dice al shell qué progtwig puede ejecutar el script.

  #! / usr / bin / env python 

se resuelve en una ruta al binario de Python.

Puedes probar este problema usando virtualenv

Aquí está test.py

 #! /usr/bin/env python import sys print(sys.version) 

Crear entornos virtuales

 virtualenv test2.6 -p /usr/bin/python2.6 virtualenv test2.7 -p /usr/bin/python2.7 

Activa cada entorno y luego comprueba las diferencias.

 echo $PATH ./test.py 

Me parece que los archivos se ejecutan igual sin esa línea.

Si es así, ¿entonces quizás estás ejecutando el progtwig Python en Windows? Windows no usa esa línea; en su lugar, usa la extensión de nombre de archivo para ejecutar el progtwig asociado con la extensión de archivo.

Sin embargo, en 2011, se desarrolló un “lanzador de Python” que, en cierta medida, 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 lanzador se instala opcionalmente como py.exe mediante la instalación de Python y se puede asociar con archivos .py para que el iniciador verifique esa línea y, a su vez, inicie la versión del intérprete de Python especificada.

Si está ejecutando su script en un entorno virtual, diga venv , luego ejecutando which python mientras trabaja en venv 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:

  • Si carga el script en un repository, está obligando a otros usuarios a tener el mismo nombre de entorno virtual . Esto es si primero identifican el problema.
  • No podrá ejecutar el script en múltiples entornos virtuales incluso si tuviera todos los paquetes necesarios en otros entornos virtuales.

Por lo tanto, para agregar a la respuesta de Jonathan , el shebang ideal es #!/usr/bin/env python , no solo para la portabilidad en todos los sistemas operativos, sino también para la portabilidad en entornos virtuales.

Simplemente especifica qué intérprete desea utilizar. Para entender 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 para hacer tu script ejecutable. Después de esto, cuando hagas ./test.py deberías obtener un error que dice:

  File "./test.py", line 2 print "test" ^ SyntaxError: Missing parentheses in call to 'print' 

porque python3 no es compatible con el operador de impresión.

Ahora ve y cambia la primera línea de tu código a:

 #!/usr/bin/env python2 

y funcionará, imprimiendo la test a la salida estándar, porque python2 es compatible con el operador de impresión. Entonces, ahora has aprendido cómo cambiar entre los intérpretes de script.

Esto significa más información histórica que una respuesta “real”.

Recuerda que en el pasado tenías MUCHOS sistemas operativos tipo UNIX, cuyos diseñadores tenían su propia idea de dónde colocar las cosas, y en ocasiones no incluían Python, Perl, Bash, o muchas otras cosas de GNU / Open Source. .

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 construyó el suyo propio y lo puso en ~ / bin

Solaris fue lo peor en lo que he trabajado, parcialmente como la transición de Berkeley Unix a System V. Podrías 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 puedo recordar si vinculó los binarios en / usr / bin o no.

Ah, y algunas veces / usr / bin estaba en un servidor NFS [2].

Así que la utilidad env fue desarrollada para solucionar esto.

Luego podría escribir #!/bin/env interpreter y siempre que el camino fuera correcto, las cosas tendrían una posibilidad razonable de ejecutarse. Por supuesto, razonable (para Python y Perl) significaba que también había establecido las variables ambientales adecuadas. Para bash / ksh / zsh simplemente funcionó.

Esto era importante porque la gente pasaba los scripts de shell (como perl y python) y si codificaba / usr / bin / python en su estación de trabajo Red Hat Linux, iba a fallar en un SGI … bueno, no , Creo que IRIX puso python en el lugar correcto. Pero en una estación de Sparc podría no funcionar en absoluto.

Extraño mi estación sparc. Pero no mucho. Ok, ahora me tienes dando vueltas en E-Bay. Bastages.

[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 me puse ni un nabo ni una cebolla en mi cinturón.

Teniendo en cuenta los problemas de portabilidad entre python2 y python3 , siempre debe especificar cualquiera de las versiones a menos que su progtwig sea compatible con ambas.

Algunas distribuciones están enviando python enlace simbólico a python3 por un tiempo, no confíe en que python sea python2 .

Esto es enfatizado por PEP 394 :

Para tolerar las diferencias entre plataformas, todo el código nuevo que necesite invocar el intérprete de Python no debe especificar python, sino que debe especificar python2 o python3 (o las versiones más específicas de python2.x y python3.x; consulte las Notas de migración ) . Esta distinción debe hacerse en shebangs, al invocar desde un script de shell, al invocar a través de la llamada a system (), o al invocar en cualquier otro contexto.

Le dice al intérprete con qué versión de python ejecutar el progtwig cuando tiene varias versiones de python.

esto le dice al script dónde está el directorio de python!

 #! /usr/bin/env python