Como iniciar um script com ambiente limpo?

15

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.
balki
fonte
Encontrado perguntas semelhantes, mas não mostra como fazer a partir shebang: unix.stackexchange.com/questions/48994/...
balki
5
Você não pode fazer isso de shebang. O shebang pode aceitar apenas um argumento.
Jordanm # 03

Respostas:

7

A razão pela qual isso não funciona é porque ele vê -i /bin/shcomo um único argumento para env. Geralmente isso seria 2 argumentos, -ie /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 CLEANEDvariá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.

Patrick
fonte
envdos coreutils do GNU agora têm uma opção -Spara solucionar problemas semelhantes a este, mas não exatamente o mesmo. Por exemplo #!/usr/bin/env -S perl -T.
Weijun Zhou
Apenas tentei. Também funciona para a pergunta original. Basta usar #!/usr/bin/env -S -i /bin/sh. Esteja ciente dos problemas de portabilidade.
Weijun Zhou 22/11
3

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 execquando o ambiente não estiver limpo (por exemplo, $ HOME está definido):

[ "$HOME" != "" ] && exec -c $0
RSFalcon7
fonte
Agradável. Só não faça env -i festa como eu fiz e depois perguntam por que suas variáveis env ainda estão definidas (claro recursos festança .bashrc e amigos 8)
Neil McGill
2

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 -eset -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 -econfiguraçã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"
maxschlepzig
fonte
0

$ cat script.sh

#!/bin/env -i /bin/sh

Infelizmente, não vai funcionar dessa maneira - o Linux considera -i /bin/shcomo um argumento a ser passado env(veja Shebang ).

poige
fonte
0

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 perlcom 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_SIZEexista 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: - /

perlprocessa 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, @ARGVnormalmente contém apenas os argumentos e $0conté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 -cargumento extra ) que a antiga AT&T ksh93faz:

#!/bin/ksh /usr/bin/env -i /bin/sh

embora talvez kshnão seja tão comum hoje em dia ;-)

( bashpossui 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 execuse -apara fazer ARGV[0](e, portanto $_) apenas "bash" e usar -cpara 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 unsetas 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.

mr.spuratic
fonte