Se os scripts do shell começarem #!/bin/bash
, eles sempre serão executados com bash
from /bin
. Se eles no entanto começar com #!/usr/bin/env bash
, eles vão procurar bash
em $PATH
e, em seguida, começar com o primeiro que possam encontrar.
Por que isso seria útil? Suponha que você queira executar bash
scripts, que exijam o bash 4.x ou mais recente, mas seu sistema só possui bash
3.x instalado e atualmente sua distribuição não oferece uma versão mais recente ou você não é administrador e não pode alterar o que está instalado nesse sistema .
Obviamente, você pode baixar o código-fonte do bash e criar seu próprio bash do zero, colocando-o como, ~/bin
por exemplo. E você também pode modificar sua $PATH
variável em seu .bash_profile
arquivo para incluir ~/bin
como a primeira entrada ( PATH=$HOME/bin:$PATH
pois ~
não será expandida $PATH
). Se você ligar agora bash
, o shell primeiro procurará por ele $PATH
em ordem, para que comece com ~/bin
onde encontrará o seu bash
. O mesmo acontece se os scripts procurarem bash
usar #!/usr/bin/env bash
, portanto, esses scripts agora estariam trabalhando no seu sistema usando sua bash
compilação personalizada .
Uma desvantagem é que isso pode levar a um comportamento inesperado, por exemplo, o mesmo script na mesma máquina pode ser executado com diferentes intérpretes para diferentes ambientes ou usuários com diferentes caminhos de pesquisa, causando todo tipo de dor de cabeça.
A maior desvantagem env
é que alguns sistemas permitem apenas um argumento, então você não pode fazer isso#!/usr/bin/env <interpreter> <arg>
, pois os sistemas o verão <interpreter> <arg>
como um argumento (eles o tratarão como se a expressão estivesse citada) e, assim env
, procurarão um intérprete chamado <interpreter> <arg>
. Observe que isso não é um problema do env
próprio comando, que sempre permite a passagem de vários parâmetros, mas com o analisador shebang do sistema que analisa essa linha antes mesmo de chamar env
. Enquanto isso, isso foi corrigido na maioria dos sistemas, mas se seu script quiser ser ultra portátil, você não pode confiar que isso foi corrigido no sistema em que você estará executando.
Pode até ter implicações de segurança, por exemplo, se sudo
não foi configurado para limpar o ambiente ou $PATH
foi excluído da limpeza. Deixe-me demonstrar isso:
Geralmente /bin
é um local bem protegido, só root
é capaz de mudar qualquer coisa lá. Seu diretório inicial não é, no entanto, qualquer programa que você executa, é capaz de fazer alterações nele. Isso significa que o código malicioso pode colocar um falso bash
em algum diretório oculto, modificá-lo .bash_profile
para incluir esse diretório no seu $PATH
, para que todos os scripts usados #!/usr/bin/env bash
acabem sendo executados com esse falsobash
. Se sudo
mantém $PATH
, você está com um grande problema.
Por exemplo, considere que uma ferramenta cria um arquivo ~/.evil/bash
com o seguinte conteúdo:
#!/bin/bash
if [ $EUID -eq 0 ]; then
echo "All your base are belong to us..."
# We are root - do whatever you want to do
fi
/bin/bash "$@"
Vamos fazer um script simples sample.sh
:
#!/usr/bin/env bash
echo "Hello World"
Prova de conceito (em um sistema em que sudo
fica $PATH
):
$ ./sample.sh
Hello World
$ sudo ./sample.sh
Hello World
$ export PATH="$HOME/.evil:$PATH"
$ ./sample.sh
Hello World
$ sudo ./sample.sh
All your base are belong to us...
Hello World
Geralmente, as conchas clássicas devem estar localizadas /bin
e, se você não quiser colocá-las lá por qualquer motivo, não é um problema colocar um link simbólico /bin
que aponte para seus locais reais (ou talvez /bin
ele próprio seja um link simbólico), então Eu sempre iria com #!/bin/sh
e#!/bin/bash
. Há muita coisa que poderia quebrar se não funcionasse mais. Não é que o POSIX exija essa posição (o POSIX não padroniza os nomes dos caminhos e, portanto, nem sequer padroniza o recurso shebang), mas eles são tão comuns que, mesmo que um sistema não ofereça um /bin/sh
, provavelmente ainda entenderá #!/bin/sh
e saiba o que fazer com ele, e pode ser apenas para compatibilidade com o código existente.
Mas para intérpretes opcionais mais modernos, não padrão e opcionais, como Perl, PHP, Python ou Ruby, isso não é realmente especificado em nenhum lugar onde eles devem estar localizados. Eles podem estar em /usr/bin
mas eles podem também estar em /usr/local/bin
ou num ramo hierarquia completamente diferente ( /opt/...
, /Applications/...
, etc.). É por isso que eles costumam usar a #!/usr/bin/env xxx
sintaxe shebang.