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


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


820
2018-03-11 23:50


origen


Respuestas:


Si tiene varias versiones de Python instaladas, /usr/bin/env se asegurará de que el intérprete utilizado sea el primero en su entorno $PATH. La alternativa sería codificar algo como #!/usr/bin/python; Está bien, pero menos flexible.

En Unix, un ejecutable el archivo que debe interpretarse puede indicar qué intérprete utilizar al tener un #! al comienzo de la primera línea, seguido por el intérprete (y cualquier señal que pueda necesitar).

Si está hablando 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 esa secuencia de comandos a una plataforma con una base de Unix, como Linux, Mac, etc.).


902
2018-03-11 23:52



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

En informática, un shebang (también llamado hashbang, hashpling, pound bang o crunchbang) se refiere a los caracteres "#!" cuando son los primeros dos 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.

Ver también el 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 parece útil mantener una línea de shebang genérica en scripts únicos (como los que escribo al responder preguntas en SO), para que pueda probarlos rápidamente en Windows y ArchLinux.

los 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 el PATH Variable ambiental. Los argumentos restantes se pasan como argumentos a ese programa.


222
2018-03-11 23:52



Ampliando un poco las otras respuestas, aquí hay un pequeño ejemplo de cómo sus scripts de línea de comandos pueden meterse en problemas por el uso incauto de /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 los comandos python versionados que normalmente se instalan con la mayoría de las pitones:

$ 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 una python3 nombre:

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

135
2018-03-12 00:35



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 guión
  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 automáticamente ignora los contenidos de la línea shebang.

los env el comando logra (2.) y (3.). Para citar "grawity"

Un uso común de la env comando es lanzar intérpretes, haciendo   uso del hecho de que env buscará $ PATH para el comando que se le dice   almorzar. Dado que la línea shebang requiere un camino absoluto para ser   especificado, y desde la ubicación de varios intérpretes (perl, bash,   pitón) puede variar mucho, es común usar:

#!/usr/bin/env perlen 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 usuario   sistema...

Por otro lado, env casi siempre está en / usr / bin / env. (Excepto en   casos cuando no lo es; algunos sistemas pueden usar / bin / env, pero eso es   Ocasión bastante rara y solo ocurre en sistemas que no son Linux.


78
2018-03-26 00:07



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 caparazón (desde la línea de comando). Esto se conoce como el "El asunto! "y se usa en diversas situaciones, no solo con los scripts de Python.

Aquí, instruye al caparazón para comenzar un versión específica de Python (para ocuparse del resto del archivo).


38
2018-03-11 23:58



Tal vez 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

Llamándolo directamente como un programa normal o un script bash, necesita escribir esa línea para especificar al sistema qué programa usar para ejecutarlo (y también hacerlo ejecutable con chmod 755)


37
2018-01-17 11:13



La razón principal para hacer esto es hacer que la secuencia de comandos sea portátil en todos los entornos de sistema operativo.

Por ejemplo, bajo mingw, las secuencias de comandos python utilizan:

#!/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 swix / hw de 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 la secuencia de comandos sea portátil en todos mediante el uso de:

#!/usr/bin/env python

34
2017-07-20 22:34



los exec llamada al sistema del kernel de Linux entiende shebangs (#!) de forma nativa

Cuando lo haces en bash:

./something

en Linux, esto llama al exec llamada al 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]! = '!'))

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

Si eso es cierto, el kernel de Linux analiza el resto de la línea, lo que hace que otra llamada ejecutiva con ruta /usr/bin/env python y 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 personaje de comentario.

Y sí, puedes hacer un ciclo infinito con:

#!/a

y un archivo ejecutable en /a

#! resulta ser legible por humanos, pero eso no es obligatorio.

Si el archivo comenzó con diferentes bytes, entonces el exec la llamada al sistema usaría un manejador 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 verifica los bytes 7f 45 4c 46 (que también es legible para humanos .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 kernel un archivo ejecutable ejecutable bajo Linux?

Finalmente, puede agregar sus propios manejadores de shebang con binfmt_misc mecanismo. Por ejemplo, puedes agregar un controlador personalizado para .jar archivos. Este mecanismo incluso admite manejadores por extensión de archivo. Otra aplicación es ejecute ejecutables de forma transparente de una arquitectura diferente con QEMU.

No creo que POSIX especifique shebangs sin embargo: https://unix.stackexchange.com/a/346214/32558 , aunque menciona en las secciones de justificación, y en la forma "si el sistema admite secuencias de comandos ejecutables, puede pasar algo".


23
2017-12-02 18:29



Probablemente tenga sentido enfatizar una cosa que la mayoría ha pasado por alto, lo que puede evitar una comprensión inmediata. Cuando escribes python en la terminal, normalmente no proporciona una ruta completa. En cambio, el ejecutable está mirando hacia arriba PATH Variable ambiental. A su vez, cuando quiere ejecutar un programa Python directamente, /path/to/app.py, uno debe decirle al intérprete de comandos qué intérprete usar (a través del hashbang, lo que los otros contribuyentes están explicando arriba).

Hashbang espera una ruta completa a un intérprete Por lo tanto, para ejecutar su programa Python directamente, debe proporcionar una ruta completa al archivo binario de Python, que varía significativamente, especialmente si se considera el uso de un programa Python. virtualenv. Para abordar la portabilidad, el truco con /usr/bin/env es usado. El último está destinado originalmente a alterar el entorno in situ y ejecutar un comando en él. Cuando no se proporciona ninguna alteración, ejecuta el comando en el entorno actual, lo que resulta efectivamente en el mismo PATH búsqueda que hace el truco.

Fuente de Unix stackexchange


19
2018-03-18 09:31



Es una forma recomendada, propuesta en la documentación:

2.2.2. Guiones de Python ejecutables

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

#! /usr/bin/env python3.2

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


12
2017-12-11 09:34



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.


10
2018-03-11 23:53