No cabeçalho de um script Bash, qual é a diferença entre essas duas instruções:
#!/usr/bin/env bash
#!/usr/bin/bash
Quando consultei a env
página de manual , recebo esta definição:
env - run a program in a modified environment
O que isso significa?
Respostas:
Executando um meio de comando
/usr/bin/env
tem a vantagem de olhar para o que a versão padrão do programa está na sua 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 o encontrará.
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 desejar dar suporte ao Linux, pois o POSIX é vago sobre como a linha deve ser interpretada e o Linux interpreta tudo após o primeiro espaço para denotar um único argumento. Você pode usar/usr/bin/env -S
em algumas versõesenv
para contornar isso, mas o script se tornará ainda menos portátil e quebrará em sistemas bastante recentes (por exemplo, até o Ubuntu 16.04, se não depois).Outra desvantagem é que, como você não está chamando um executável explícito, há o potencial de erros e de problemas de segurança nos sistemas multiusuário (se alguém conseguisse chamar o executável
bash
no seu caminho, por exemplo).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 preferido, pois limita as possibilidades de injeção de código.
fonte
#!/usr/bin/env echo Hello
reclama:/usr/bin/env: echo Hello: No such file or directory
. Aparentemente, trataecho Hello
como um único argumento para/usr/bin/env
.env
comando certamente permite que argumentos sejam passados para o comando. A questão é a semântica da#!
linha, e isso depende do kernel. Os kernels recentes do Linux permitem coisas assim#!/usr/bin/env command args
, mas os antigos do Linux e outros sistemas não.Usar
#!/usr/bin/env NAME
faz com que o shell procure a 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.fonte
Em vez de definir explicitamente o caminho para o intérprete como em
/usr/bin/bash/
, usando o comando env, o intérprete é procurado e iniciado a partir de onde quer que seja encontrado. Isso tem vantagens e desvantagensfonte
Se os scripts do shell começarem
#!/bin/bash
, eles sempre serão executados combash
from/bin
. Se eles no entanto começar com#!/usr/bin/env bash
, eles vão procurarbash
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ó possuibash
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 agorabash
, o shell primeiro procurará por ele$PATH
em ordem, para que comece com~/bin
onde encontrará o seubash
. O mesmo acontece se os scripts procurarembash
usar#!/usr/bin/env bash
, portanto, esses scripts agora estariam trabalhando no seu sistema usando suabash
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, assimenv
, procurarão um intérprete chamado<interpreter> <arg>
. Observe que isso não é um problema doenv
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 chamarenv
. 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 falsobash
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
. Sesudo
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:Vamos fazer um script simples
sample.sh
:Prova de conceito (em um sistema em que
sudo
fica$PATH
):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.fonte
Acho útil, porque quando eu não sabia sobre o env, antes de começar a escrever o script, estava fazendo o seguinte:
e então eu estava modificando essa linha no arquivo para shebang.
Eu estava fazendo isso, porque nem sempre me lembro onde está o nodejs no meu computador - / usr / bin / ou / bin /, portanto, para mim,
env
é muito útil. Talvez haja detalhes com isso, mas esta é a minha razãofonte