Se os processos herdam o ambiente do pai, por que precisamos exportar?

72

Li aqui que o objetivo de exportum shell é disponibilizar a variável para subprocessos iniciados no shell.

No entanto, também li aqui e aqui que "os processos herdam o ambiente do pai (o processo que os iniciou)".

Se for esse o caso, por que precisamos export? o que estou perdendo?

As variáveis ​​de shell não fazem parte do ambiente por padrão? Qual é a diferença?

Amelio Vazquez-Reina
fonte

Respostas:

75

Você supõe que as variáveis ​​do shell estão no ambiente . Isto está incorreto. O exportcomando é o que define um nome para estar no ambiente. Portanto:

a=1 b=2
export b

resulta no shell atual sabendo que se $aexpande para 1 e $b2, mas os subprocessos não saberão nada sobre aisso porque não fazem parte do ambiente (mesmo no shell atual).

Algumas ferramentas úteis:

  • set: Útil para visualizar os parâmetros do shell atual, exportados ou não
  • set -k: Define os argumentos atribuídos no ambiente. Considerarf() { set -k; env; }; f a=1
  • set -a: Diz ao shell para colocar qualquer nome definido no ambiente. Como colocar exportantes de cada tarefa. Útil para .envarquivos, como em set -a; . .env; set +a.
  • export: Diz ao shell para colocar um nome no ambiente. Exportação e atribuição são duas operações completamente diferentes.
  • env: Como um comando externo, você envpode apenas falar sobre o ambiente herdado , portanto, é útil para verificar a integridade.
  • env -i: Útil para limpar o ambiente antes de iniciar um subprocesso.

Alternativas para export:

  1. name=val command # A atribuição antes do comando exporta esse nome para o comando.
  2. declare/local -x name # Exporta nome, particularmente útil em funções de shell quando você deseja evitar expor o nome ao escopo externo.
  3. set -a # Exporta todas as atribuições a seguir.
kojiro
fonte
3
set -ké para que você possa usar cmd ENVVAR=valueno lugar de ENVVAR=value cmd, que não funcionará no seu exemplo, a menos que tenha set -ksido executado antes da chamada f. Além disso, poucas conchas o suportam atualmente e apenas para compatibilidade com o shell Bourne. No shell Bourne (ou Korn), isso não funcionaria para funções. E porque afeta a análise de shell, ele deve estar em vigor no momento em que o shell o código que o utiliza lá.
Stéphane Chazelas
11
Você também pode mencionarset -a
Stéphane Chazelas 7/17/17
24

Há uma diferença entre variáveis ​​de shell e variáveis ​​de ambiente. Se você definir uma variável de shell sem exportincluí-la, ela não será incluída no ambiente de processos e, portanto, não será herdada de seus filhos.

Usando exportvocê diz ao shell para adicionar a variável shell ao ambiente. Você pode testar isso usando printenv(que apenas imprime seu ambiente stdout, já que é um processo filho no qual você vê o efeito das exportvariáveis):

#!/bin/sh

MYVAR="my cool variable"

echo "Without export:"
printenv | grep MYVAR

echo "With export:"
export MYVAR
printenv | grep MYVAR
Andreas Wiese
fonte
6

Uma variável, uma vez exportada, faz parte do ambiente. PATHé exportado no próprio shell, enquanto variáveis ​​personalizadas podem ser exportadas conforme necessário. Usando algum código de configuração:

$ cat subshell.sh 
#!/usr/bin/env bash
declare | grep -e '^PATH=' -e '^foo='

Comparar

$ cat test.sh 
#!/usr/bin/env bash
export PATH=/bin
export foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test.sh 
PATH=/bin
foo=bar
PATH=/bin
foo=bar

Com

$ cat test2.sh 
#!/usr/bin/env bash
PATH=/bin
foo=bar
declare | grep -e '^PATH=' -e '^foo='
./subshell.sh
$ ./test2.sh 
PATH=/bin
foo=bar
PATH=/bin

Como foonão é exportado pelo shell e test2.shnunca exportado, ele não fazia parte do ambiente da subshell.shúltima execução.

l0b0
fonte