Env ou não env

32

Qual é a diferença entre o comando

$ env FOO=bar baz

e

$ FOO=bar baz

Que efeito envtem?

August Karlstrom
fonte
4
É uma pergunta secundária, mas como é o próprio recurso chamado quando você define uma variável de ambiente para um único subcomando como esse? Sempre tive dificuldade em encontrar informações sobre isso, porque não sei como se chama.
John Cromartie
1
@JohnCromartie, você deve fazer isso como uma pergunta.
Cjm
1
Para o bash, está documentado aqui: gnu.org/software/bash/manual/…
glenn jackman
2
@JohnCromartie É um componente opcional de todos os comandos do shell, por isso está na seção "Comandos Simples" da maioria dos manuais de shell. Para o POSIX, isso estaria aqui . A Glenn vinculou a seção análoga do manual do bash para você.
Jw013
Definir uma variável que não existe por meio de uma atribuição cria uma variável de shell. A configuração via ENV ou a exportação da variável empurram a variável para o ambiente de execução do shell. Alterar o valor de uma variável existente atualizará o valor do ambiente de execução, se houver, caso contrário, altere-o nas variáveis ​​internas do shell.
21414 Johan

Respostas:

26

Eles são funcionalmente equivalentes.

A principal diferença é que env FOO=bar bazenvolve a invocação de um processo intermediário entre o shell e baz, onde, como FOO=bar bazo shell, invoca diretamente baz.
Então, a esse respeito, FOO=bar bazé o preferido.

As únicas situações em que me encontro usando env FOO=baré onde tenho que passar um comando para outro comando.
Como exemplo específico, digamos que eu tenha um script de wrapper que execute algumas modificações no ambiente e, em seguida, chame execo comando que foi passado para ele, como:

#!/bin/bash
FOO=bob
some stuff
exec "$@"

Se você executá-lo como myscript FOO=bar baz, o execerro exec FOO=bar bazserá inválido.
Em vez disso, você o chama como o myscript env FOO=bar bazque é executado como exec env FOO=bar baze é perfeitamente válido.

Patrick
fonte
1
Você pode fazer FOO=bar exec bazisso, para não precisar envno seu último ponto.
Stéphane Chazelas
Quando você execusa algo, ele usa seu ambiente atual?
Glenn Jackman
1
Ditto @StephaneChazelas, e você também pode sudo FOO=bar bazpassar variáveis ​​de ambiente sem a necessidade env.
Mike Miller
1
@StephaneChazelas que só funciona se eu quiser colocar FOO=baro script. Se FOOnem sempre é bar, não quero codificá-lo e passá-lo para dentro.
Patrick
@glennjackman sim, desde que as variáveis ​​sejam exportadas ou passadas antes do exec, como FOO=bar exec baz.
22314 Patrick
14

Neste exemplo em particular, não há diferença efetiva, supondo que seu shell seja um shell compatível com POSIX e assumindo que bazseja um executável e não um shell embutido.

Se seu shell não for um shell compatível com POSIX, por exemplo , cshou tcsha sintaxe

FOO=bar baz

não funciona e não há sintaxe de shell equivalente. Para esses shells, o envcomando é a única maneira de substituir ou injetar variáveis ​​de ambiente para um único comando.

Se bazfor um shell embutido, digamos, fcpor exemplo, envnão dará os mesmos resultados, porque envestá executando um novo processo em vez de ser executado diretamente pelo shell de comando. Além disso, não existe um fcexecutável, ele só pode ser executado como um shell embutido por causa da maneira como ele interage com o ambiente do shell e, portanto env, nunca funcionará com um embutido como esse fc.

Além disso, envoferece a -iopção, que permite iniciar um comando em um ambiente vazio com apenas um conjunto especificado de variáveis ​​de ambiente. Portanto, envpode ser muito útil para iniciar processos em ambientes higienizados, por exemplo

env -i HOME=/tmp/homedir "PATH=`getconf PATH`" "TERM=$TERM" FOO=bar baz
Mike Miller
fonte
Quando eu costumava usar tcsh, escrevia (setenv FOO bar; baz)para obter a função equivalente.
Barmar 21/05
6

Além do que já foi dito

VAR=value cmd args > redirs

sendo um recurso shell (Bourne / POSIX), você está limitado no nome das variáveis ​​de ambiente às quais passa cmd. Eles precisam ser nomes de variáveis ​​válidos do shell e não devem ser somente leitura ou variáveis ​​especiais para o shell.

Por exemplo, você não pode fazer:

1=foo cmd

Ou

+++=bar cmd

bash não permite que você faça:

SHELLOPTS=xtrace cmd

Enquanto você pode fazer:

env 1=foo cmd
env +++=bar cmd
env '=baz' cmd

(não que você queira ou deva fazer isso). Ou:

env SHELLOPTS=xtrace cmd

(Às vezes eu preciso fazer isso).

Observe que envvocê ainda não pode passar uma sequência de variáveis ​​de ambiente que não contenha um =(não que você queira fazer isso também).

Stéphane Chazelas
fonte
2

Um uso de envé permitir a $PATHpesquisa de executáveis ​​em linhas shebang (porque envconsidera a $PATHpesquisa ao executável). Isso é útil se o executável que você deseja chamar estiver em locais diferentes em máquinas diferentes. Por exemplo,

#!/usr/bin/env perl

na primeira linha de um script com conjunto de bits executável, ele será executado com Perl, independentemente de estar instalado /usr/bin/perlem /usr/local/bin/perlou em um local completamente diferente, desde que o diretório esteja no caminho.

É claro que a pesquisa de caminho traz um risco adicional, mas, então, o risco não é maior do que se você tivesse escrito explicitamente perl yourscript.pl, o que também procura perl no caminho de pesquisa.

celtschk
fonte
2

Outro momento em que envé realmente útil é se você deseja controlar o ambiente completamente. Eu corro um programa de servidor (Informix, caso você não consiga adivinhar) cujo ambiente eu quero controlar completamente. Eu o executo envno final de um script que define um monte de variáveis ​​com os valores corretos:

env -i HOME="$IXD" \
       INFORMIXDIR="$IXD" \
       INFORMIXSERVER="$IXS" \
       ${IXC:+INFORMIXCONCSMCFG="$IXC"} \
       ${IXH:+INFORMIXSQLHOSTS="$IXH"} \
       IFX_LISTEN_TIMEOUT=3 \
       ONCONFIG="onconfig.$IXS" \
       PATH="/bin:/usr/bin:$IXD/bin" \
       SHELL=/bin/ksh \
       TZ=UTC0 \
    $ONINIT "$@"

A -iopção zaps o ambiente existente. As VAR=valueopções subseqüentes definem as variáveis ​​de ambiente que eu quero definir; o nome do programa está $ONINITe todos os argumentos da linha de comando são passados ​​literalmente com "$@".

A ${IXH:+INFORMIXSQLHOSTS="$IXH"}construção passa apenas INFORMIXSQLHOSTS="$IXH"para envse $IXHestiver definida como um valor não vazio.

Jonathan Leffler
fonte