Como o / usr / bin / env sabe qual programa usar?

62

Quando uso o shebang #!/usr/bin/env pythonpara executar um script, como o sistema sabe qual pythonusar? se procuro um pythoncaminho bin nas variáveis ​​de ambiente, não encontro nada.

env | grep -i python
tMC
fonte
6
oh eu penso que eu percebi isso out- ele só procura o seu $ PATH para 'python'
TMC
Eu também me perguntei sobre isso. E por que / usr / bin / env? ao contrário de / bin / env ou env, se estiver obtendo apenas uma lista de caminhos do env?
Faheem Mitha
Apenas 'env' não funcionará porque precisa ser o caminho completo. O programa 'env' é normalmente encontrado em / user / bin / env. Em algumas distros, também pode ser encontrado como / bin / env, mas é mais seguro usar / usr / bin / env.
Rettops

Respostas:

55

O shebang espera que um caminho completo para o intérprete seja usado para que a seguinte sintaxe esteja incorreta:

#!python

Definir um caminho completo como este pode funcionar:

#!/usr/local/bin/python

mas seria não portátil como python pode ser instalado em /bin, /opt/python/binou onde quer outro local.

Usando env

#!/usr/bin/env python

é um método que permite uma maneira portátil de especificar para o sistema operacional um caminho completo equivalente ao local onde pythonestá localizado pela primeira vez no PATH.

jlliagre
fonte
57

A linha shebang (de “sharp bang”, ie #!) é processada pelo kernel. O kernel não quer saber sobre variáveis ​​de ambiente como PATH. Portanto, o nome na linha shebang deve ser um caminho absoluto para um executável. Você também pode especificar um argumento adicional para passar para esse executável antes do nome do script (com restrições dependentes do sistema, não vou entrar aqui). Por exemplo, para um script Python, você pode especificar

#!/usr/bin/python

na primeira linha, e quando você executar o script, o kernel será executado /usr/bin/python /path/to/script. Mas isso não é conveniente: você precisa especificar o caminho completo do comando. O que se tem pythonem /usr/binem algumas máquinas e /usr/local/binnos outros? Ou você deseja configurá PATH- /home/joe/opt/python-2.5/binlo para usar uma versão específica do Python? Como o kernel não fará a PATHpesquisa por você, a idéia é fazer com que o kernel execute um comando que, por sua vez, procure o intérprete desejado no PATH:

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

Isso path-lookup-commanddeve tomar o nome de um executável como argumento e procurá-lo PATHe executá-lo: o kernel será executado /fixed/path/to/path-lookup-command python /path/to/script. Por acaso, o envcomando faz exatamente isso. Seu principal objetivo é executar um comando com um ambiente diferente, mas como ele procura o nome do comando $PATH, é perfeito para o nosso propósito aqui.

Embora isso não é garantido oficialmente, sistemas históricos Unix fornecido envno /usr/bine sistemas modernos têm mantido esse local precisamente por causa do uso generalizado de #!/usr/bin/env. Portanto, na prática, a maneira de especificar que um script deve ser executado pelo interpretador Python favorito do usuário é

#!/usr/bin/env python
Gilles 'SO- parar de ser mau'
fonte
2
qual é o preferido entre enve which? desde que também obterá o executável mais qualificado do meu ambiente PATH.
precisa saber é o seguinte
8
@NikhilMulley whichencontra o executável e imprime seu caminho. envlocaliza o programa especificado pelo primeiro argumento e o executa, passando os argumentos restantes.
Kevin
3
assim é que envé uma versão whichessencial de essencialmente.
Nikhil Mulley 02/02
7

Certo, então corra:

env | grep PATH

Seu $ PATH é uma lista de diretórios. O Unix passará por essa lista de diretórios, em ordem, até encontrar "python".

Você pode ver qual diretório ele encontra com o comando 'what':

which python
Dan Rue
fonte
Curiosamente, estou vendo uma diferença no python sys.pathentre um env ativado $ 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']) e ./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