Para env ou não env

32

Qual é a diferença entre o comando

$ env FOO=bar baz

e

$ FOO=bar baz

Qual o efeito que o env tem?

    
por August Karlstrom 15.05.2014 / 18:51

5 respostas

25

Eles são funcionalmente equivalentes.

A principal diferença é que env FOO=bar baz envolve invocar um processo intermediário entre o shell e o baz , em que, como com FOO=bar baz , o 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 in é onde eu tenho que passar um comando para outro comando.
Como um exemplo específico, digamos que possuo um script de wrapper que realiza algumas modificações do ambiente e, em seguida, chama exec no comando que foi passado para ele, como:

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

Se você executá-lo como myscript FOO=bar baz , o exec lançará um erro, pois exec FOO=bar baz é inválido.
Em vez disso, você o chama como myscript env FOO=bar baz , que é executado como exec env FOO=bar baz e é perfeitamente válido.

    
por 15.05.2014 / 19:28
13

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

Se o seu shell não for um shell compatível com POSIX, por exemplo, csh ou tcsh , a sintaxe

FOO=bar baz

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

Se baz for um shell embutido, digamos fc por exemplo, então env não fornecerá os mesmos resultados, porque env está executando um novo processo em vez de ser executado diretamente pelo shell de comando. Além disso, não há fc executá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á como um fc .

Além disso, env oferece a opção -i , que permite iniciar um comando em um ambiente vazio com apenas um conjunto especificado de variáveis de ambiente. Então env pode ser muito útil para iniciar processos em ambientes higienizados, por exemplo

env -i HOME=/tmp/homedir "PATH='getconf PATH'" "TERM=$TERM" FOO=bar baz
    
por 15.05.2014 / 19:25
6

Além do que já foi dito

VAR=value cmd args > redirs

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

Por exemplo, você não pode fazer:

1=foo cmd

Ou

+++=bar cmd

bash não permite:

SHELLOPTS=xtrace cmd

Enquanto você pode fazer:

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

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

env SHELLOPTS=xtrace cmd

(às vezes preciso fazer isso).

Note que com env você ainda não pode passar uma string de variável de ambiente que não contenha = (não que você queira fazer isso também).

    
por 15.05.2014 / 21:20
2

Um uso de env é permitir a pesquisa $PATH de executáveis em linhas shebang (porque env considera o $PATH ao pesquisar pelo executável). Isso é útil se o executável que você deseja invocar pode estar em lugares diferentes em máquinas diferentes. Por exemplo,

#!/usr/bin/env perl

na primeira linha de um script com bit executável irá executar este script com Perl, não importa se ele está instalado em /usr/bin/perl ou /usr/local/bin/perl ou em um lugar completamente diferente, desde que o diretório esteja no caminho.

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

    
por 16.05.2014 / 18:44
2

Outra hora em que env é realmente útil é se você deseja controlar o ambiente completamente. Eu corro um programa servidor (Informix, no caso de você não pode adivinhar) cujo ambiente eu quero controlar completamente. Eu o executo usando env no final de um script que define um monte de variáveis para 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 opção -i ativa o ambiente existente. As opções VAR=value subseqüentes definem as variáveis de ambiente que desejo definir; o nome do programa está em $ONINIT , e todos os argumentos da linha de comando são passados textualmente com "$@" .

A construção ${IXH:+INFORMIXSQLHOSTS="$IXH"} apenas passa INFORMIXSQLHOSTS="$IXH" para env se $IXH estiver definido como um valor não vazio.

    
por 16.05.2014 / 19:39

Tags