Eu tentei o seguinte, mas parece não funcionar:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Eu tentei o seguinte, mas parece não funcionar:
$ cat script.sh
#!/bin/env -i /bin/sh
/bin/env
$ script.sh
/bin/env: invalid option -- ' '
Try `/bin/env --help' for more information.
Respostas:
A razão pela qual isso não funciona é porque ele vê -i /bin/sh
como um único argumento para env
. Geralmente isso seria 2 argumentos, -i
e /bin/sh
. Esta é apenas uma limitação do shebang. De jeito nenhum.
No entanto, você ainda pode executar esta tarefa, apenas de uma maneira diferente.
Se você deseja que essa tarefa seja executada pelo próprio script, e não precise fazer algo como isso env -i script.sh
, é possível executar o script novamente.
#!/bin/sh
[ -z "$CLEANED" ] && exec /bin/env -i CLEANED=1 /bin/sh "$0" "$@"
Isso fará com que o script seja reexecutado se a CLEANED
variável de ambiente não estiver definida. Em seguida, na reexecução, ele define a variável para garantir que ela não entre em loop.
env
dos coreutils do GNU agora têm uma opção -S
para solucionar problemas semelhantes a este, mas não exatamente o mesmo. Por exemplo #!/usr/bin/env -S perl -T
.
#!/usr/bin/env -S -i /bin/sh
. Esteja ciente dos problemas de portabilidade.
Execute seu script com env -i
:
env -i script.sh
E o script como de costume:
#!/bin/sh
# ... your code here
Se você deseja executar com um ambiente limpo, sem dizer isso explicitamente ao executar. Eduardo Ivanec fornece algumas idéias nesta resposta . Você pode chamar seu script recursivamente exec
quando o ambiente não estiver limpo (por exemplo, $ HOME está definido):
[ "$HOME" != "" ] && exec -c $0
Com o bash, você pode fazer assim:
#!/usr/bin/bash
set -e
set -u
[ -v HOME ] && exec -c "$0" "$@"
# continue with the rest of the script
# e.g. print the cleaned environment:
export
o set -e
set -u
comandos e não são estritamente necessários, mas eu os incluo para demonstrar que essa abordagem não depende do acesso a variáveis não definidas (como [ "$HOME" != "" ]
seria o caso) e é compatível com uma set -e
configuração.
Testando o HOME
variável deve ser seguro porque o bash executa scripts no modo não interativo, ou seja, arquivos de configuração como ~/.bashrc
(onde variáveis de ambiente podem ser definidas) não são originados durante a inicialização.
Exemplo de saída:
declare -x OLDPWD
declare -x PWD="/home/juser"
declare -x SHLVL="1"
A limitação shebang de 2 argumentos do Linux (interpeter + argumento único) é observada na maioria das respostas, mas dizer que isso não pode ser feito está incorreto - você só precisa mudar para um intérprete que possa fazer algo útil com um único argumento:
#!/usr/bin/perl -we%ENV=();exec "/bin/sh " . join " ", map "'$_'", @ARGV;
# your sh script here
O que isso faz é chamar perl
com um script de uma linha ( -e
) que limpa %ENV
(mais barato que env -i
) e chama exec /bin/sh
, citando corretamente os argumentos. Mais longeperl
lógica pode ser adicionada, se necessário (embora não BINPRM_BUF_SIZE
exista muito no Linux, pois você está limitado a caracteres, o que provavelmente é 128)
Infelizmente, isso é específico do Linux, não funcionará em um sistema que permita vários argumentos shebang: - /
perl
processa essa sequência como um argumento único, portanto não é citada acima, como você faria normalmente perl -e ...
na linha de comando (se você adicionar aspas, estas são preservadas, o perl vê apenas uma string literal, com avisos queixam-se de que é inútil constante).
Observe também que há uma ligeira mudança no comportamento quando usado dessa maneira, @ARGV
normalmente contém apenas os argumentos e $0
contém o script, mas com esse shebang $ARGV[0]
está o nome do script (e $0
é -e
), o que facilita um pouco.
Você também pode resolver isso com um intérprete que "reprocessa" sua linha de comando (sem um -c
argumento extra ) que a antiga AT&T ksh93
faz:
#!/bin/ksh /usr/bin/env -i /bin/sh
embora talvez ksh
não seja tão comum hoje em dia ;-)
( bash
possui um recurso semelhante --wordexp
, mas é "não documentado" nas versões em que trabalha e não é ativado em tempo de compilação nas versões em que está documentado: - / Também não pode ser usado para isso, pois precisa de dois argumentos. ..)
Além disso, efetivamente uma variação nas respostas de @Patrick e @ maxschlepzig:
#!/bin/bash
[ "$_" != bash ] && exec -c -a "bash" /bin/bash "$0" "$@"
# your script here
Em vez de usar uma nova variável, ela usa a _
variável " " especial , se não estiver definida exatamente como "bash", substitua o script por exec
use -a
para fazer ARGV[0]
(e, portanto $_
) apenas "bash" e usar -c
para limpar o ambiente.
Como alternativa, se é aceitável limpar o ambiente no início do script (somente bash):
#!/bin/sh
unset $(compgen -e)
# your script here
Que usa compgen
(auxiliar de conclusão) para listar os nomes de todas as variáveis de ambiente exportadas e unset
as seleciona de uma só vez.
Consulte também Vários argumentos no shebang para obter mais detalhes sobre o problema geral do comportamento do shebang.