Comment / usr / bin / env sait-il quel programme utiliser?

62

Lorsque j'utilise shebang #!/usr/bin/env pythonpour exécuter un script, comment le système sait-il lequel pythonutiliser? si je cherche un pythonchemin bin dans les variables d'environnement, je ne trouve rien.

env | grep -i python
tMC
la source
6
oh je pense que je l'ai compris - il cherche juste dans votre $ PATH pour 'python'
tMC
Je me suis aussi posé la question. Et pourquoi / usr / bin / env? par opposition à / bin / env ou env, s’il s’agit juste d’obtenir une liste de chemins d’env?
Faheem Mitha
Juste "env" ne fonctionnera pas car il doit s'agir d'un chemin complet. Le programme 'env' se trouve généralement dans / user / bin / env. Sur certaines distributions, on peut aussi trouver / bin / env, mais il est plus prudent d’utiliser / usr / bin / env.
rettops

Réponses:

55

Shebang s'attend à ce qu'un chemin d'accès complet à l'interpréteur soit utilisé afin que la syntaxe suivante soit incorrecte:

#!python

Définir un chemin complet comme celui-ci pourrait fonctionner:

#!/usr/local/bin/python

mais serait non portable python peut être installé /bin, /opt/python/binou un autre endroit où.

En utilisant env

#!/usr/bin/env python

est une méthode permettant à un moyen portable de spécifier au système d’exploitation un chemin complet équivalent à celui où se pythontrouve d’abord situé dans PATH.

jlliagre
la source
57

La ligne shebang (de «sharp bang», c’est-à-dire #!) est traitée par le noyau. Le noyau ne veut pas connaître les variables d'environnement telles que PATH. Donc, le nom sur la ligne shebang doit être un chemin absolu vers un exécutable. Vous pouvez également spécifier un argument supplémentaire à transmettre à cet exécutable avant le nom du script (avec des restrictions dépendant du système, je ne vais pas entrer ici). Par exemple, pour un script Python, vous pouvez spécifier

#!/usr/bin/python

sur la première ligne, et lorsque vous exécutez le script, le noyau s’exécutera /usr/bin/python /path/to/script. Mais ce n'est pas pratique: vous devez spécifier le chemin complet de la commande. Que faire si vous avez pythondans /usr/binsur certaines machines et /usr/local/binsur les autres? Ou vous voulez définir votre PATHà de /home/joe/opt/python-2.5/binmanière à utiliser une version spécifique de Python? Puisque le noyau ne fait pas la PATHrecherche pour vous, l’idée est de faire en sorte que le noyau exécute une commande qui, à son tour, recherche l’interpréteur souhaité dans PATH:

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

Cela path-lookup-commanddoit prendre le nom d'un exécutable en tant qu'argument, le rechercher PATHet l'exécuter: le noyau s'exécutera /fixed/path/to/path-lookup-command python /path/to/script. Il se trouve que la envcommande fait exactement cela. Son objectif principal est d'exécuter une commande dans un environnement différent, mais comme il recherche le nom de la commande $PATH, il convient parfaitement à notre propos.

Bien que ce ne soit pas officiellement garanti, les systèmes Unix historiques fournis envdans /usr/bin, et les systèmes modernes ont gardé cet endroit précisément en raison de l'utilisation généralisée de #!/usr/bin/env. Ainsi, en pratique, la manière de spécifier qu'un script doit être exécuté par l'interpréteur Python préféré de l'utilisateur est la suivante:

#!/usr/bin/env python
Gilles, arrête de faire le mal
la source
2
lequel est préféré entre envet which? depuis lequel obtiendra également le fichier exécutable le plus éligible de mon environnement PATH.
Nikhil Mulley
8
@NikhilMulley whichtrouve l'exécutable et affiche son chemin. envtrouve le programme spécifié par le premier argument et l'exécute en lui transmettant les arguments restants.
Kevin
3
Il en va de même pour la envversion eval which.
Nikhil Mulley
7

Bon, alors courez:

env | grep PATH

Votre $ PATH est une liste de répertoires. Unix va parcourir cette liste de répertoires, dans l'ordre, jusqu'à ce qu'il trouve "python".

Vous pouvez voir quel répertoire il trouve avec la commande 'which':

which python
Dan Rue
la source
Fait intéressant, je vois une différence dans le python sys.pathentre un env $ 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']) et ./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']) activés .
ThorSummoner