Estou interessado em definir variáveis ambientais de uma instância de shell de outra. Então eu decidi fazer alguma pesquisa. Depois de ler um número de perguntas sobre isso eu decidi testá-lo.
Eu criei duas conchas A e B (PID 420), ambas em execução zsh
. A partir do shell, AI executou o seguinte.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
No shell B, quando executo env
, posso ver que a variável FOO está realmente definida com um valor de bar. Isso me faz pensar que o FOO foi inicializado com sucesso no ambiente do shell B. No entanto, se eu tentar imprimir o FOO, recebo uma linha vazia, indicando que ela não está definida. Para mim, parece que há uma contradição aqui.
Isso foi testado no meu próprio sistema Arch GNU / Linux e em uma VM do Ubuntu. Também testei isso em bash
que a variável nem apareceu em env. Isso, apesar de decepcionante para mim, faz sentido se o shell armazena em cache uma cópia de seu ambiente no momento da desova e a utiliza apenas (o que foi sugerido em uma das perguntas vinculadas). Isso ainda não responde por que zsh
pode ver a variável.
Por que a saída de echo $FOO
vazia?
EDITAR
Após a entrada nos comentários, decidi fazer um pouco mais de teste. Os resultados podem ser vistos nas tabelas abaixo. Na primeira coluna está o shell no qual a FOO
variável foi injetada. A primeira linha contém o comando cuja saída pode ser vista abaixo dela. A variável FOO
foi injectado usando: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Os comandos específicos do zsh: zsh -c '...'
também foram testados usando o bash. Os resultados foram idênticos, sua saída foi omitida por brevidade.
Arch GNU / Linux, zsh 5.3.1, bash 4.4.12 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
Ubuntu 16.04.2 LTS, zsh 5.1.1, bash 4.3.48 (1)
| | env | grep FOO | echo $FOO | zsh -c 'env | grep FOO' | zsh -c 'echo $FOO' | After export FOO |
|------|------------------|-----------|---------------------------|----------------------|-----------------------------------|
| zsh | FOO=bar | | FOO=bar | bar | No Change |
| bash | | bar | | | Value of FOO visible in all tests |
O exposto acima parece implicar que os resultados são agnósticos na distribuição. Isso não me diz muito mais do que zsh
e bash
lida com a configuração de variáveis de maneira diferente. Além disso, export FOO
possui um comportamento muito diferente nesse contexto, dependendo do shell. Esperançosamente, esses testes podem deixar algo claro para outra pessoa.
zsh -c 'echo $FOO'
(use aspas simples!)? Você pode ver isso então?env
) veem o ambiente modificado.zsh
no GDB não a torna visível como uma variável de shell, mas faz com que ela seja passada para processos filho (como você observou), ao definir um parabash
o torna visível como uma variável de shell, mas não faz com que ela seja passada para processos filhos! Parece que o zsh e o bash usam estratégias diferentes para gerenciar variáveis, com o zsh que rastreia variáveis que não são de ambiente e o bash armazena tudo em seu ambiente, que é higienizado ao iniciar um filho (sem sub-shell).export FOO
embash
?Respostas:
A maioria dos shells não usa a
getenv()
/setenv()
/putenv()
API.Na inicialização, eles criam variáveis de shell para cada variável de ambiente. Eles serão armazenados em estruturas internas que precisam carregar outras informações, como se a variável é exportada, somente leitura ... Eles não podem usar as bibliotecas
environ
para isso.Da mesma forma, e por essa razão, eles não vão usar
execlp()
,execvp()
para executar comandos, mas chamar aexecve()
chamada de sistema diretamente, o cálculo daenvp[]
matriz com base na lista de suas variáveis exportadas.Portanto, no seu caso
gdb
, você precisará adicionar uma entrada à tabela interna de variáveis dos shells ou possivelmente chamar a função correta que faria com que ele interpretasse umexport VAR=value
código para atualizar a tabela por si só.Quanto ao porquê você vê uma diferença entre
bash
ezsh
quando você chamarsetenv()
emgdb
, eu suspeito que é porque você está chamandosetenv()
antes dos inicializa shell, por exemplo, ao entrarmain()
.Você notará
bash
'smain()
é 'int main(int argc, char* argv[], char* envp[])
(ebash
mapeia as variáveis desses ambientesenvp[]
) enquantozsh
's éint main(int argc, char* argv[])
ezsh
obtém as variáveis'environ
.setenv()
modifica,environ
mas não pode modificarenvp[]
no local (somente leitura em vários sistemas, bem como as seqüências de caracteres para as quais esses ponteiros apontam).De qualquer forma, após a leitura do shell
environ
na inicialização, o usosetenv()
seria ineficaz, pois o shell não usa maisenviron
(ougetenv()
) posteriormente.fonte