Exportar uma variável env para estar disponível em todas as subcascas e possível de ser modificada?

22

Suponha que eu tenha

export MY_VAR=0

no ~/.bashrc.

Eu tenho um terminal gnome aberto e, neste terminal, altero o $MY_VARvalor para 200. Então, se eu fizer

echo $MY_VAR

neste terminal, 200é mostrado.

Agora, abri outra guia no meu terminal gnome e fiz

echo $MY_VAR

... e em vez de 200, eu tenho 0.

O que devo fazer para manter o valor 200 quando um terminal modifica uma variável de ambiente, disponibilizando essa modificação (configurando para 200) para todas as subcascas subseqüentes e outras? Isso é possível?

Alguém ainda usa você no MS-DOS
fonte

Respostas:

23

Uma cópia do ambiente se propaga para subconchas, portanto, isso funciona:

$ export MY_VAR=200
$ bash
$ echo $MY_VAR
200

mas como é uma cópia, você não pode obter esse valor até o shell pai - não alterando o ambiente, pelo menos.

Parece que você realmente quer ir um passo adiante, que é criar algo que atue como uma variável global, compartilhada por shells "irmãos" iniciados separadamente dos pais - como sua nova guia no Gnome Terminal.

Principalmente, a resposta é "você não pode, porque as variáveis ​​de ambiente não funcionam dessa maneira". No entanto, há outra resposta, que é, bem, você sempre pode hackear alguma coisa. Uma abordagem seria escrever o valor da variável em um arquivo, como ~/.myvar, e depois incluí-lo ~/.bashrc. Em seguida, cada novo shell começará com o valor lido desse arquivo.

Você poderia dar um passo adiante - criar ~/.myvarno formato MYVAR=200e depois definir PROMPT_COMMAND=source ~/.myvar, o que faria com que o valor fosse relido toda vez que você receber um novo prompt. Ainda não é uma variável global compartilhada, mas está começando a agir assim. Porém, ele não será ativado até que um prompt volte, o que, dependendo do que você está tentando fazer, pode ser uma limitação séria.

E então, é claro, a próxima coisa a fazer é gravar automaticamente as alterações ~/.myvar. Isso fica um pouco mais complicado, e eu vou parar neste momento, porque, na verdade, as variáveis ​​de ambiente não foram feitas para serem um mecanismo de comunicação entre shell, e é melhor encontrar outra maneira de fazê-lo.

mattdm
fonte
10
Eu posso ouvir o shell guinchando sob a tortura
Sim, desculpe-me. Por isso parei. :)
mattdm
"que é fazer algo que age como uma variável global" - Bem, de fato, era isso que eu estava tentando realizar. O ~ / .myvar não é bonito, mas funciona. Você tem outra sugestão?
Alguém ainda usa o MS-DOS
2
Bem, vamos voltar um pouco. Por que você deseja uma variável global?
mattdm
1
@mattdm: Eu tenho algumas "burocracias" que tenho que obedecer. Um deles é um monte de códigos que preciso confirmar juntamente com um comentário. Esses códigos estão agora em uma hierarquia de pastas (home / user / projects / projectcode / code1 / code2). Eu criei uma função que extrai code1 e code2 para env vars (então, quando eu preciso fazer uma atividade, eu apenas chamo a função dentro do dir com os códigos), e eles, ao confirmar, eu uso o vim e existem algumas funções que leia esses vars e coloque um comentário automaticamente. Eu acho que usar arquivos para isso pode ser uma solução.
Alguém ainda usa o MS-DOS
13

Suponha que eu tenho export MY_VAR=0em ~/.bashrc.

Esse é o seu erro aí. Você deve definir suas variáveis ​​de ambiente ~/.profile, que são lidas quando você efetua login. São ~/.bashrclidas toda vez que você inicia um shell; quando você inicia o shell interno, ele substitui MY_VAR. Se você não tivesse feito isso, sua variável de ambiente se propagaria para baixo.

Para mais informações sobre ~/.bashrcvs ~/.profile, veja minhas postagens anteriores sobre este tópico .

Observe que a propagação ascendente (obter um valor modificado do subshell refletido automaticamente no shell pai) não é possível, ponto final.

Gilles 'SO- parar de ser mau'
fonte
3

Não use variáveis ​​de ambiente. Use arquivos.

Para impedir que os processos se interponham ao atualizar / ler o arquivo, use arquivos de bloqueio e pequenos scripts de atualização de front-end, cujo objetivo é apenas atualizar um arquivo com $ 1, se não estiver bloqueado. Os arquivos de bloqueio são implementados verificando basicamente se existe um arquivo específico (/var/run/yourscript.lck) e, se existir, aguarde o arquivo desaparecer por um tempo e falhe se não existir. Além disso, você deve excluir o arquivo de bloqueio ao concluir a atualização do arquivo.

Esteja preparado para lidar com uma situação em que um script não pode atualizar um arquivo porque o arquivo está ocupado.

LawrenceC
fonte
8
Um truque: use diretórios em vez de arquivos para bloquear, porque mkdirfunciona como um teste e criação atômico.
mattdm
1
Se vocês querem falar sobre o bloqueio, então você pode muito bem estar usandoflock(2)
Ehtesh Choudhury
@mattdm Descobri que um link simbólico ln -s dummy lockfile(mesmo se quebrado) também pode funcionar, pois falhará se o link simbólico já existir. Gostaria de saber uma maneira de testar se isso é realmente 100% seguro.
Poder de Aquário
1

Quando acabei de pesquisar esta questão, eu estava tentando resolver o problema de atualizar o estado (ou seja, variáveis ​​de shell) de fora das subcascas. Para que se possa atribuir variáveis, digamos, dentro de um pipeline - e a atribuição seja visível de forma transparente para o pai.

Obviamente, isso não é possível de uma maneira simples, porque partes individuais de um pipeline são executadas em subcascas, que são forkeditadas a partir do shell pai e, portanto, possuem memória que é a visão de cópia na gravação na memória do pai. No entanto, eu supunha que uma solução fina e transparente fosse possível com base no tipo de IPCs de " memória compartilhada " .

E eu até encontrei uma implementação exatamente desse design ... mas é em Perl.

Adicionando esta resposta de qualquer maneira como uma possível solução.

ulidtko
fonte