Eles são definidos pelo processo
Os outros respondentes me ajudaram a entender que o escopo da variável shell é sobre processos e seus descendentes .
Quando você digita um comando como ls
na linha de comando, na verdade você está bifurcando um processo para executar o programa ls
. O novo processo tem seu shell como pai.
Qualquer processo pode ter suas próprias variáveis "locais", que não são passadas para processos filhos. Também pode definir variáveis de "ambiente", que são. Usando export
cria uma variável de ambiente. Em ambos os casos, processos não relacionados (pares do original) não verão a variável; estamos controlando apenas o que os processos filhos veem.
Suponha que você tenha um shell bash, que chamaremos A. Você digita bash
, que cria um shell bash de processo filho, que chamaremos B. Qualquer coisa que você chamou de export
on em A ainda será definido em B.
Agora, em B, você diz FOO=b
. Uma das duas coisas acontecerá:
- Se B não recebeu (de A) uma variável de ambiente chamada
FOO
, ela criará uma variável local. Filhos de B não o receberão (a menos que B chameexport
). - Se B fez receber (de A) uma variável de ambiente chamada
FOO
, irá modificá-la para si e seus subsequentes filhos bifurcados . Filhos de B verão o valor que B designou. No entanto, isso não afetará A.
Aqui está uma demonstração rápida.
FOO=a # set "local" environment variable
echo $FOO # 'a'
bash # forks a child process for the new shell
echo $FOO # not set
exit # return to original shell
echo $FOO # still 'a'
export FOO # make FOO an environment variable
bash # fork a new "child" shell
echo $FOO # outputs 'a'
FOO=b # modifies environment (not local) variable
bash # fork "grandchild" shell
echo $FOO # outputs 'b'
exit # back to child shell
exit # back to original shell
echo $FOO # outputs 'a'
Tudo isso explica o meu problema original: eu defino GEM_HOME
no meu shell, mas quando chamei bundle install
, isso criou um processo filho. Como não usei export
, o processo filho não recebeu GEM_HOME
do shell.
Não exportar
Você pode "não exportar" uma variável - impedir que ela seja passada para crianças - usando export -n FOO
.
export FOO=a # Set environment variable
bash # fork a shell
echo $FOO # outputs 'a'
export -n FOO # remove environment var for children
bash # fork a shell
echo $FOO # Not set
exit # back up a level
echo $FOO # outputs 'a' - still a local variable