Acabei de encontrar um problema que me mostra que não sou claro sobre o escopo das variáveis do shell.
Eu estava tentando usar bundle install
, que é um comando Ruby que usa o valor de $GEM_HOME
para fazer seu trabalho. Eu tinha definido $GEM_HOME
, mas o comando ignorou esse valor até que eu usei export
, como em export GEM_HOME=/some/path
.
Li que isso torna a variável de alguma forma "global" (também conhecida como variável de ambiente ), mas não entendo o que isso significa. Eu sei sobre globais em programação, mas não em programas distintos.
Além disso, como minha configuração dessas variáveis se aplica apenas à sessão atual do shell, como eu as definiria para, por exemplo, um processo daemonizado?
Quais escopos podem ter variáveis de shell?
fonte
FOO=bar
, isso define o valor do processo atual do shell. Se eu executar um programa como (bundle install
), que cria um processo filho, ao qual não há acessoFOO
. Mas se eu tivesse ditoexport FOO=bar
, o processo filho (e seus descendentes) teria acesso a ele. Um deles poderia, por sua vez, pedirexport FOO=buzz
para alterar o valor de seus descendentes, ou apenasFOO=buzz
alterar o valor apenas para si. Isso é certo?Pelo menos as variáveis under
ksh
ebash
, podem ter três escopos, e não dois, como todas as respostas restantes estão dizendo no momento.Além dos escopos variáveis exportados (isto é, do ambiente) e dos escopos variáveis não exportados, há também um terceiro mais restrito para variáveis locais de função.
Variáveis declaradas em funções de shell com o
typeset
token são visíveis apenas dentro das funções em que são declaradas e nas (sub) funções chamadas a partir daí.Este
ksh
/bash
código:produz esta saída:
Como você pode ver, a variável exportada é exibida nos três primeiros locais, as variáveis não exportadas não são exibidas fora do shell atual e a variável local da função não tem valor fora da própria função. O último teste não mostra nenhum valor, isso ocorre porque as variáveis exportadas não são compartilhadas entre os shells, ou seja, elas só podem ser herdadas e o valor herdado não pode ser afetado posteriormente pelo shell pai.
Observe que esse último comportamento é bem diferente do comportamento do Windows, no qual você pode usar as Variáveis do sistema totalmente globais e compartilhadas por todos os processos.
fonte
Eles têm escopo definido pelo processo
Os outros respondedores 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, você está realmente bifurcação um processo para executar ols
programa. 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 filho. Também pode definir variáveis de "ambiente", quais são. Usar
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 apenas controlando o que os processos filhos veem.Suponha que você tenha um shell bash, que chamaremos de A. Você digita
bash
, que cria um shell bash do processo filho, que chamaremos de B. Qualquer coisa que você chamouexport
em A ainda será definida em B.Agora, em B, você diz
FOO=b
. Uma de duas coisas acontecerá:FOO
, ela criará uma variável local. Filhos de B não o receberão (a menos que B ligueexport
).FOO
, ele irá modificá-lo para si e seus filhos posteriormente bifurcados . Filhos de B verão o valor que B atribuiu. No entanto, isso não afetará A.Aqui está uma demonstração rápida.
Tudo isso explica meu problema original: coloquei
GEM_HOME
no meu shell, mas quando ligueibundle install
, isso criou um processo filho. Por não ter usadoexport
, o processo filho não recebeu o shellGEM_HOME
.Não exportando
Você pode "cancelar a exportação" de uma variável - impedindo que ela seja passada para crianças - usando
export -n FOO
.fonte
A melhor explicação que posso encontrar sobre a exportação é esta:
http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_03_02.html
O conjunto de variáveis dentro de um subshell ou shell filho é visível apenas para o subshell no qual está definido. A variável exportada é realmente feita para ser uma variável de ambiente. Portanto, para ficar claro, o seu
bundle install
executa seu próprio shell, que não vê o mesmo$GEM_HOME
, a menos que seja transformada em umaenvironment
variável conhecida como exportada.Você pode dar uma olhada na documentação para escopo variável aqui:
http://www.tldp.org/LDP/abs/html/subshells.html
fonte
FOO=bar
; você tem que usarexport
para torná-lo um. Pergunta corrigida em conformidade.Há uma hierarquia de escopos variáveis, conforme o esperado.
Meio Ambiente
O escopo mais externo é o meio ambiente. Esse é o único escopo gerenciado pelo sistema operacional e, portanto, é garantido que existe para todos os processos. Quando um processo é iniciado, ele recebe uma cópia do ambiente de seus pais, após o que os dois se tornam independentes: modificar o ambiente do filho não altera o ambiente dos pais e modificar o ambiente dos pais não altera o de um filho já existente.
Variáveis do shell
Os shells têm sua própria noção de variáveis. É aqui que as coisas começam a ficar um pouco confusas.
Quando você atribui um valor a uma variável em um shell, e essa variável já existe no ambiente, a variável de ambiente recebe o novo valor. No entanto, se a variável não estiver no ambiente, ela se tornará uma variável do shell . As variáveis do shell existem apenas dentro do processo do shell, semelhante à forma como as variáveis Ruby existem apenas dentro de um script Ruby. Eles nunca são herdados por processos filhos.
Aqui é onde a
export
palavra - chave entra em ação. Ele copia uma variável de shell no ambiente do processo de shell, possibilitando a herança de processos filhos.Variáveis locais
Variáveis locais são variáveis de shell com escopo definido para os blocos de código que as contêm. Você declara variáveis locais com a
typeset
palavra - chave (portátil) oulocal
oudeclare
(Bash). Como outras variáveis de shell, as variáveis locais não são herdadas pelos processos filhos. Também variáveis locais não podem ser exportadas.fonte