Desativar uma variável de ambiente para um comando

24

Eu posso correr ENV_VAR=value commandpara executar commandcom um valor específico para ENV_VAR. Qual é o equivalente a unset ENV_VARpara command?

Alexey Romanov
fonte
7
Além: commandé uma escolha infeliz de espaços reservados, pois na verdade existe um comando interno com esse nome. mycommandou somecommandisso pode ser um hábito melhor para entrar.
Charles Duffy
@CharlesDuffy, eu costumo usar cmdpara isso.
Stéphane Chazelas

Respostas:

35

Além da -iopção, que limpa todo o ambiente, o POSIX envnão fornece nenhuma maneira de desmarcar uma variável.

No entanto, com algumas envimplementações (incluindo GNU, busybox'e FreeBSD, pelo menos), você pode:

env -u ENV_VAR command

O que funcionaria para remover todas as instâncias de uma ENV_VARvariável do ambiente (observe que ela não funciona para a variável de ambiente com um nome vazio ( env -u ''gera um erro ou é ineficaz dependendo da implementação, mesmo que todos aceitem env '=value', provavelmente uma limitação incorridos pela unsetenv()função C, que o POSIX requer para retornar um erro para a cadeia vazia, enquanto não houver essa limitação para putenv())).

Portably (em shells POSIX), você pode fazer:

(unset -v ENV_VAR; exec command)

(observe que, com alguns shells, usar execpode alterar o que commandé executado: executa o sistema de arquivos em vez de uma função ou um componente interno, por exemplo (e ignoraria a aliasexpansão obviamente), como envacima. Você gostaria de omitir esses casos) .

Mas isso não funcionará para variáveis ​​de ambiente que tenham um nome que não possa ser mapeado para uma variável de shell (observe que alguns shells, como mkshessas, tirariam essas variáveis ​​do ambiente na inicialização de qualquer maneira) ou variáveis ​​marcadas como somente leitura.

-vé para o shell Bourne e bashcujo unsetsem -vpoderia desabilitar uma ENV_VAR função se não houvesse variável com esse nome. A maioria dos outros shells não desabilita funções, a menos que você passe na -fopção. (improvável que faça diferença na prática).

(Também tenha cuidado com o bug / falha de bash/ mksh/ yashcuja unset, em algumas circunstâncias, pode não desmarcar a variável, mas revelar a variável em um escopo externo )

Se perlestiver disponível, você pode fazer:

perl -e 'delete $ENV{shift@ARGV}; exec @ARGV or die$!' ENV_VAR command

O que funcionará mesmo para a variável de ambiente com um nome vazio.

Agora, tudo isso não funcionará se você desejar alterar uma variável de ambiente para um builtin ou função e não desejar que eles sejam executados em um subshell, como em bash:

env -u LANG printf -v var %.3f 1.2 # would run /usr/bin/printf instead
(unset -v LANG; printf -v var %.3f 1.2) # changes to $var lost afterwards

(aqui desabilitar LANG como uma abordagem equivocada para garantir . seja usado e entendido como o separador decimal. Seria melhor usar LC_ALL=C printf...isso)

Com alguns shells, você pode criar um escopo local para a variável usando uma função:

without() {
  local "$1" # $1 variable declared as initially unset in bash¹
  shift
  "$@"
}
without LANG printf -v var %.3f 1.2

Com zsh, você também pode usar uma função anônima:

(){local ENV_VAR; command}

Essa abordagem não funcionará em alguns shells (como os baseados no shell Almquist), localque não declaram a variável como inicialmente desativada (mas herdam o valor e os atributos). Nessas, você pode fazer local ENV_VAR; unset ENV_VAR, mas não faça isso mkshou yash(em typesetvez localdisso), pois isso não funcionaria, unsetpois apenas cancelaria olocal .

¹ Também tenha cuidado que em bash , o local ENV_VAR(embora não definido) reteria o atributo de exportação . Portanto, se commandfosse uma função que atribui um valor ENV_VAR, a variável estará disponível no ambiente de comandos chamados posteriormente. unset ENV_VARlimparia esse atributo. Ou você pode usar o local +x ENV_VARque também garantiria uma lista limpa (a menos que essa variável tenha sido declarada somente leitura, mas não há nada que você possa fazer sobre isso bash).

Stéphane Chazelas
fonte
11
É uma pergunta separada, mas que diabos é uma variável de ambiente com um nome vazio e como você a usaria - mesmo para algum tipo de exploração? Você não precisaria escrever um programa que leia o ambiente e procure algo parecido com isso?
Joe
@ Joe, tente por exemplo env '=foo' python -c 'import os; print os.environ[""]'. Não espero que muitas pessoas queiram definir uma variável assim.
Stéphane Chazelas
9

Não há equivalente direto, até onde eu saiba; você pode usar um subshell:

(unset ENV_VAR; exec command)
Stephen Kitt
fonte
(unset ENV_VAR; exec somecommand)se você quiser ser equivalente ao original em eficiência (consumindo o subshell). Como é, isso adiciona um garfo extra.
Charles Duffy
11
@ Charles, de fato, embora alguns shells o façam automaticamente, pois esse commandé o último comando na invocação do subshell.
Stephen Kitt
+1 porque é fácil digitar para uso interativo. Eu uso subshells para alterações pontuais no ambiente de shell de uma linha, em vez de lembrar que é env -u.
Peter Cordes
0

Você pode usar ENV_VAR= command

Na verdade, isso não desmarca a variável, mas pode ser útil em muitos casos (os scripts de shell geralmente usam apenas test -npara verificar se uma variável está definida):

$ export ENV_VAR=foo
$ mycommand
ENV_VAR: foo
$ ENV_VAR=bar mycommand
ENV_VAR: bar
$ ENV_VAR= mycommand
ENV_VAR: 
GnP
fonte