Qual é a diferença entre set, export e env e quando devo usar cada um?

112

De vez em quando eu mostro um script bash e me parece que existem algumas maneiras de definir uma variável:

key=value
env key=value
export key=value

Quando você está dentro de um script ou de um único comando (por exemplo, costumo encadear uma variável com um iniciador do Wine para definir o prefixo correto do Wine), elas parecem ser totalmente intercambiáveis, mas certamente esse não pode ser o caso.

Qual é a diferença entre esses três métodos e você pode me dar um exemplo de quando eu gostaria especificamente de usar cada um?

Definitivamente relacionado a Qual é a diferença entre `VAR = ...` e `export VAR = ...`? mas também quero saber como isso envse encaixa e alguns exemplos mostrando os benefícios de cada um também seriam bons :)

Oli
fonte
5
Observe que a export key=valuesintaxe é estendida e não deve ser usada em scripts portáteis (ou seja #! /bin/sh).
Simon Richter

Respostas:

110

Vamos considerar um exemplo específico. O grepcomando usa uma variável de ambiente chamada GREP_OPTIONSpara definir opções padrão.

Agora. Dado que o arquivo test.txtcontém as seguintes linhas:

line one
line two

executando o comando grep one test.txtretornará

line one

Se você executar grep com a -vopção, ele retornará as linhas não correspondentes, portanto a saída será

line two

Agora tentaremos definir a opção com uma variável ambiental.

  1. As variáveis ​​de ambiente definidas sem exportnão serão herdadas no ambiente dos comandos que você está chamando.

    GREP_OPTIONS='-v'
    grep one test.txt

    O resultado:

    line one

    Obviamente, a opção -vnão foi aprovada grep.

    Você deseja usar este formulário quando estiver configurando uma variável apenas para o shell usar, por exemplo, se for i in * ; dovocê não deseja exportar $i.

  2. No entanto, a variável é transmitida para o ambiente dessa linha de comando específica, para que você possa fazer

    GREP_OPTIONS='-v' grep one test.txt

    que retornará o esperado

    line two

    Você usa este formulário para alterar temporariamente o ambiente dessa instância específica do programa iniciado.

  3. Exportar uma variável faz com que a variável seja herdada:

    export GREP_OPTIONS='-v'
    grep one test.txt

    retorna agora

    line two

    Essa é a maneira mais comum de definir variáveis ​​para uso de processos iniciados posteriormente em um shell

  4. Tudo isso foi feito no bash. exporté um bash embutido; VAR=whateveré a sintaxe do bash. env, por outro lado, é um programa em si. Quando envé chamado, acontece o seguinte:

    1. O comando envé executado como um novo processo
    2. env modifica o ambiente e
    3. chama o comando que foi fornecido como argumento. O envprocesso é substituído pelo commandprocesso.

    Exemplo:

    env GREP_OPTIONS='-v' grep one test.txt

    Este comando iniciará dois novos processos: (i) env e (ii) grep (na verdade, o segundo processo substituirá o primeiro). Do ponto de vista do grepprocesso, o resultado é exatamente o mesmo que executar

    GREP_OPTIONS='-v' grep one test.txt

    No entanto, você pode usar esse idioma se estiver fora do bash ou não quiser iniciar outro shell (por exemplo, quando estiver usando a exec()família de funções em vez da system()chamada).

Nota adicional sobre #!/usr/bin/env

É também por isso que o idioma #!/usr/bin/env interpreteré usado em vez de #!/usr/bin/interpreter. envnão requer um caminho completo para um programa, porque usa a execvp()função que pesquisa através da PATHvariável, exatamente como um shell, e depois se substitui pela execução do comando. Assim, ele pode ser usado para descobrir onde um intérprete (como perl ou python) "fica" no caminho.

Isso também significa que, modificando o caminho atual, você pode influenciar qual variante python será chamada. Isso possibilita o seguinte:

echo -e '#!/usr/bin/bash\n\necho I am an evil interpreter!' > python
chmod a+x ./python
export PATH=.
calibre

em vez de iniciar o Calibre, resultará em

I am an evil interpreter!
janeiro
fonte
Por que GREP_OPTIONS = '- v' grep one test.txt funciona? Eu pensei que precisava de um ponto e vírgula depois de 'v' (mas eu tentei e ele faz no trabalho de fato.)
Joe
2
Porque com um ponto e vírgula, ele é interpretado como dois comandos separados do bash; o primeiro define a variável (sem exportá-la) e o segundo começa com um ambiente que não possui a variável exportada. Sem o ponto e vírgula, no entanto, este é um comando (grep), precedido pela configuração de um ambiente local.
janeiro
De onde envvêm todas as variáveis ? Quero dizer, quando você abre um novo shell, sempre tem algumas variáveis. Então, algum programa deve ter exporteditado isso, certo?
Pithikos 30/10
1
As variáveis ​​de ambiente do @Pithikos são definidas por "buscar um ambiente". Por padrão, o bash fornecerá um bashrc em todo o sistema (ou profile.d ou bash_profile). Em seguida, ele fornece seu usuário ~ / .bashrc (e / ou ~ / .bash_profile). Qualquer um desses arquivos pode conter comandos bash para originar outros scripts, para que você possa ter variáveis ​​de ambiente provenientes de todo o lugar.
Eric
5
Que tal set var=blah?
precisa saber é o seguinte