Se os scripts do shell começarem #!/bin/bash, eles sempre serão executados com bashfrom /bin. Se eles no entanto começar com #!/usr/bin/env bash, eles vão procurar bashem $PATHe, em seguida, começar com o primeiro que possam encontrar.
Por que isso seria útil? Suponha que você queira executar bashscripts, que exijam o bash 4.x ou mais recente, mas seu sistema só possui bash3.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, ~/binpor exemplo. E você também pode modificar sua $PATHvariável em seu .bash_profilearquivo para incluir ~/bincomo a primeira entrada ( PATH=$HOME/bin:$PATHpois ~não será expandida $PATH). Se você ligar agora bash, o shell primeiro procurará por ele $PATHem ordem, para que comece com ~/binonde encontrará o seu bash. O mesmo acontece se os scripts procurarem bashusar #!/usr/bin/env bash, portanto, esses scripts agora estariam trabalhando no seu sistema usando sua bashcompilaçã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 envpró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 sudonão foi configurado para limpar o ambiente ou $PATHfoi 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 bashem algum diretório oculto, modificá-lo .bash_profilepara incluir esse diretório no seu $PATH, para que todos os scripts usados #!/usr/bin/env bashacabem sendo executados com esse falsobash . Se sudomantém $PATH, você está com um grande problema.
Por exemplo, considere que uma ferramenta cria um arquivo ~/.evil/bashcom 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 /bine, se você não quiser colocá-las lá por qualquer motivo, não é um problema colocar um link simbólico /binque aponte para seus locais reais (ou talvez /binele próprio seja um link simbólico), então Eu sempre iria com #!/bin/she#!/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/she 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/binmas eles podem também estar em /usr/local/binou num ramo hierarquia completamente diferente ( /opt/..., /Applications/..., etc.). É por isso que eles costumam usar a #!/usr/bin/env xxxsintaxe shebang.