ti-enxame.com

Qual é a diferença entre "#! / Usr / bin / env bash" e "#! / Usr / bin / bash"?

No cabeçalho de um script bash, qual é a diferença entre essas duas instruções?

  1. #!/usr/bin/env bash

  2. #!/usr/bin/bash

Quando tentei ver a página man env, obtive esta definição:

 env - run a program in a modified environment

O que isso significa?

291
tarrsalah

Executar um comando através de /usr/bin/env tem o benefício de procurar qualquer que seja a versão padrão do programa em seu atual env ironment.

Dessa forma, você não precisa procurá-lo em um local específico no sistema, pois esses caminhos podem estar em locais diferentes em sistemas diferentes. Enquanto estiver no seu caminho, ele irá encontrá-lo.

Uma desvantagem é que você não conseguirá passar mais de um argumento (por exemplo, você não conseguirá escrever /usr/bin/env awk -f) se você quiser dar suporte ao Linux, como POSIX é vago sobre como a linha deve ser interpretada e o Linux interpreta tudo depois do primeiro espaço para denotar um único argumento. Você pode usar /usr/bin/env -S em algumas versões de env para contornar isso, mas o script se tornará ainda menos portátil e invadirá sistemas bastante recentes (por exemplo, mesmo o Ubuntu 16.04, se não depois).

Outra desvantagem é que desde que você não está chamando um executável explícito, ele tem o potencial de erros, e em problemas de segurança de sistemas multiusuários (se alguém conseguiu obter seu executável chamado bash em seu caminho, por exemplo).

#!/usr/bin/env bash #lends you some flexibility on different systems
#!/usr/bin/bash     #gives you explicit control on a given system of what executable is called

Em algumas situações, o primeiro pode ser preferido (como executar scripts python com várias versões do python, sem precisar refazer a linha executável). Mas em situações em que a segurança é o foco, o último seria o preferido, já que limita as possibilidades de injeção de código.

264
Alec Bennett

O uso de #!/usr/bin/env NAME faz o Shell procurar pela primeira correspondência de NAME na variável de ambiente $ PATH. Pode ser útil se você não estiver ciente do caminho absoluto ou não quiser procurá-lo.

49
Dolphiniac

Em vez de definir explicitamente o caminho para o interpretador como em /usr/bin/bash/, usando o comando env, o interpretador é procurado e iniciado a partir de onde quer que seja encontrado pela primeira vez. Isso tem tanto psides e downsides

11
safay

Acho que é útil, porque quando eu não sabia sobre env, antes de começar a escrever script eu estava fazendo isso:

type nodejs > scriptname.js #or any other environment

e então eu estava modificando essa linha no arquivo para o Shebang.
Eu estava fazendo isso, porque nem sempre lembro onde está o nodejs no meu computador -/usr/bin/ou/bin /, então para mim o env é muito útil. Talvez haja detalhes com isso, mas esta é a minha razão

3
sudo97

Se os scripts do Shell começarem com #!/bin/bash, eles sempre serão executados com bash de /bin. Se, no entanto, eles começarem com #!/usr/bin/env bash, eles pesquisarão bash em $PATH e, em seguida, começarão com o primeiro que encontrarem.

Por que isso seria útil? Suponha que você queira executar scripts bash, que exijam bash 4.x ou mais recente, mas seu sistema tem apenas bash 3.x instalado e atualmente sua distribuição não oferece uma versão mais nova ou você não é administrador e não pode alterar o que está instalado esse sistema.

Claro, você pode baixar o código-fonte bash e construir seu próprio bash a partir do zero, colocando-o em ~/bin por exemplo. E você também pode modificar sua variável $PATH em seu arquivo .bash_profile para incluir ~/bin como a primeira entrada (PATH=$HOME/bin:$PATH como ~ não expandirá em $PATH). Se você agora chamar bash, o Shell procurará primeiro em $PATH em ordem, de modo que comece com ~/bin, onde encontrará seu bash. A mesma coisa acontece se os scripts pesquisarem bash usando #!/usr/bin/env bash, portanto, esses scripts agora estarão funcionando em seu sistema usando sua compilação bash personalizada.

Uma desvantagem é que isso pode levar a um comportamento inesperado, por ex. O mesmo script na mesma máquina pode ser executado com diferentes intérpretes para diferentes ambientes ou usuários com caminhos de pesquisa diferentes, causando todos os tipos de dores de cabeça.

A maior desvantagem com env é que alguns sistemas permitirão apenas um argumento, então você não pode fazer isso #!/usr/bin/env <interpreter> <arg>, pois os sistemas verão <interpreter> <arg> como um argumento (eles o tratarão como se a expressão tivesse sido citada) e assim env irá procurar por um argumento. intérprete chamado <interpreter> <arg>. Note que este não é um problema do próprio comando env, que sempre permitiu que múltiplos parâmetros fossem passados, mas com o analisador Shebang do sistema que analisa esta linha antes mesmo de chamar env. Enquanto isso, isso foi corrigido na maioria dos sistemas, mas se o seu script quiser ser ultra-portátil, você não pode confiar que isso foi corrigido no sistema que você estará executando.

Pode até ter implicações de segurança, por ex. se Sudo não foi configurado para limpar o ambiente ou $PATH foi excluído da limpeza. Deixe-me demonstrar isso:

Normalmente /bin é um local bem protegido, somente root é capaz de alterar qualquer coisa lá. Seu diretório pessoal não é, no entanto, qualquer programa executado pode fazer alterações nele. Isso significa que código malicioso poderia colocar um bash falso em algum diretório oculto, modificar seu .bash_profile para incluir esse diretório em seu $PATH, então todos os scripts que usam #!/usr/bin/env bash terminarão executando com o bash falso. 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 "[email protected]"

Vamos fazer um script simples sample.sh:

#!/usr/bin/env bash

echo "Hello World"

Prova de conceito (em um sistema onde Sudo mantém $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

Normalmente, os shells clássicos devem estar localizados em /bin e se você não quiser colocá-los lá por qualquer motivo, não é um problema colocar um link simbólico em /bin que aponte para seus locais reais (ou talvez /bin em si seja um link simbólico ), então eu sempre iria com #!/bin/sh e #!/bin/bash. Há muita coisa que quebraria se isso não funcionasse mais. Não é que o POSIX exigiria essa posição (o POSIX não padroniza os nomes dos caminhos e, portanto, nem padroniza o recurso Shebang), mas eles são tão comuns que, mesmo que um sistema não oferecesse um /bin/sh, provavelmente ainda entenda #!/bin/sh e saiba o que fazer com ele e que seja apenas para compatibilidade com o código existente.

Mas, para intérpretes mais modernos, não padrão e opcionais, como Perl, PHP, Python ou Ruby, ele não é realmente especificado em nenhum lugar onde deva ser localizado. Eles podem estar em /usr/bin mas podem estar em /usr/local/bin ou em uma ramificação de hierarquia completamente diferente (/opt/..., /Applications/..., etc.). É por isso que eles geralmente usam a sintaxe #!/usr/bin/env xxx Shebang.

2
Mecki