¿Cómo sabe / usr / bin / env qué programa usar?

62

Cuando uso el shebang #!/usr/bin/env pythonpara ejecutar un script, ¿cómo sabe el sistema cuál pythonusar? Si busco una pythonruta bin en las variables de entorno, no encuentro nada.

env | grep -i python
tMC
fuente
66
oh, creo que lo descubrí, solo busca en tu $ PATH 'python'
tMC
Me he preguntado sobre eso también. ¿Y por qué / usr / bin / env? a diferencia de / bin / env o env, si solo se trata de obtener una lista de rutas de env?
Faheem Mitha
Simplemente 'env' no funcionará porque tiene que ser un camino completo. El programa 'env' generalmente se encuentra en / user / bin / env. En algunas distribuciones también se puede encontrar como / bin / env, pero es más seguro ir con / usr / bin / env.
Rettops

Respuestas:

55

El shebang espera una ruta completa para que lo use el intérprete, por lo que la siguiente sintaxis sería incorrecta:

#!python

Establecer una ruta completa como esta podría funcionar:

#!/usr/local/bin/python

pero no sería portátil como pitón podría instalarse en /bin, /opt/python/bino donde sea otra ubicación.

Utilizando env

#!/usr/bin/env python

es un método que permite una forma portátil de especificar al sistema operativo una ruta completa equivalente a la que se pythonencuentra por primera vez en el PATH.

jlliagre
fuente
57

La línea shebang (de "golpe fuerte", es decir #!) es procesada por el núcleo. El núcleo no quiere saber sobre variables de entorno como PATH. Por lo tanto, el nombre en la línea shebang debe ser una ruta absoluta a un ejecutable. También puede especificar un argumento adicional para pasar a ese ejecutable antes del nombre del script (con restricciones dependientes del sistema no entraré aquí). Por ejemplo, para un script de Python, puede especificar

#!/usr/bin/python

en la primera línea, y cuando ejecutas el script, el núcleo se ejecutará de hecho /usr/bin/python /path/to/script. Pero eso no es conveniente: debe especificar la ruta completa del comando. ¿Qué pasa si usted tiene pythonen /usr/binen algunas máquinas y /usr/local/binen los demás? O si desea configurar su PATHa /home/joe/opt/python-2.5/binfin de utilizar una versión específica de Python? Como el kernel no buscará PATHpor usted, la idea es hacer que el kernel ejecute un comando que a su vez busque el intérprete deseado en PATH:

#!/fixed/path/to/path-lookup-command python

Que path-lookup-commanddebe tomar el nombre de un archivo ejecutable como argumento y búsquelo en PATHy ejecutarlo: el núcleo se ejecutará /fixed/path/to/path-lookup-command python /path/to/script. Como sucede, el envcomando hace exactamente eso. Su objetivo principal es ejecutar un comando con un entorno diferente, pero dado que busca el nombre del comando $PATH, es perfecto para nuestro propósito aquí.

Aunque esto no está garantizado oficialmente, los sistemas Unix históricos proporcionados enven /usr/bin, y los sistemas modernos han mantenido a ese lugar precisamente por el uso generalizado de #!/usr/bin/env. Entonces, en la práctica, la forma de especificar que un script debe ser ejecutado por el intérprete de Python favorito del usuario es

#!/usr/bin/env python
Gilles 'SO- deja de ser malvado'
fuente
2
¿Cuál es el preferido entre envy which? ya que también obtendré el ejecutable más elegible de mi entorno PATH.
Nikhil Mulley
8
@NikhilMulley whichencuentra el ejecutable e imprime su ruta. envencuentra el programa especificado por el primer argumento y lo ejecuta, pasándole los argumentos restantes.
Kevin
3
entonces es envuna versión eval de whichesencialmente.
Nikhil Mulley
7

Bien, entonces corre:

env | grep PATH

Su $ PATH es una lista de directorios. Unix revisará esa lista de directorios, en orden, hasta que encuentre "python".

Puedes ver qué directorio encuentra con el comando 'which':

which python
Dan Rue
fuente
Curiosamente, estoy viendo una diferencia en el pitón sys.pathentre un env activado $ env python3 ( ['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/.local/lib/python3.4/site-packages', '/usr/lib/python3.4/site-packages', '/usr/local/lib/python3.4/dist-packages', '/usr/lib/python3/dist-packages']) y ./env/bin/python3 (['', '/home/user/test', '/usr/lib/python3.4', '/usr/lib/python3.4/plat-x86_64-linux-gnu', '/usr/lib/python3.4/lib-dynload', '/home/user/test/env3/lib/python3.4/site-packages']).
ThorSummoner