Je souhaite définir des variables d'environnement d'une instance de shell à partir d'une autre. J'ai donc décidé de faire des recherches. Après avoir lu un certain nombre de questions à ce sujet, j'ai décidé de le tester.
J'ai engendré deux obus A et B (PID 420), tous deux en marche zsh
. Depuis le shell, AI a exécuté ce qui suit.
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Depuis le shell B lorsque je cours, env
je peux voir que la variable FOO est en effet définie avec une valeur de bar. Cela me fait penser que FOO a été initialisé avec succès dans l'environnement du shell B. Cependant, si j'essaie d'imprimer FOO, j'obtiens une ligne vide indiquant qu'elle n'est pas définie. Pour moi, c'est comme s'il y avait une contradiction ici.
Cela a été testé sur mon propre système Arch GNU / Linux et sur une machine virtuelle Ubuntu. J'ai également testé cela sur les bash
endroits où la variable n'apparaissait même pas en env. Bien que décevant pour moi, cela a du sens si le shell met en cache une copie de son environnement au moment du frai et ne l'utilise que (ce qui a été suggéré dans l'une des questions liées). Cela ne répond toujours pas pourquoi zsh
peut voir la variable.
Pourquoi la sortie est-elle echo $FOO
vide?
ÉDITER
Après l'entrée dans les commentaires, j'ai décidé de faire un peu plus de tests. Les résultats sont visibles dans les tableaux ci-dessous. Dans la première colonne se trouve le shell dans lequel la FOO
variable a été injectée. La première ligne contient la commande dont la sortie peut être vue en dessous. La variable FOO
a été injecté à l' aide: sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
. Les commandes spécifiques à zsh: zsh -c '...'
ont également été testées à l'aide de bash. Les résultats étaient identiques, leur sortie a été omise par souci de concision.
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 |
Ce qui précède semble impliquer que les résultats sont indépendants de la distribution. Cela ne m'en dit pas beaucoup plus zsh
et bash
gère différemment le réglage des variables. De plus, export FOO
a un comportement très différent dans ce contexte selon le shell. Espérons que ces tests puissent clarifier quelque chose pour quelqu'un d'autre.
zsh -c 'echo $FOO'
(utilisez des guillemets simples!) À la place? Le voyez-vous alors?env
) voient l'environnement modifié.zsh
dans GDB ne la rend pas visible en tant que variable shell mais la fait passer à des processus enfants (comme vous l'avez observé), alors que définir un pour lebash
rend visible en tant que variable shell mais ne le fait pas être transmis aux processus enfants! Il semble que zsh et bash utilisent différentes stratégies pour gérer les variables, avec zsh qui suit les variables non environnementales et bash stocke tout dans son environnement qu'il nettoie lors du lancement d'un enfant (non sous-shell).export FOO
dansbash
?Réponses:
La plupart des shells n'utilisent pas l' API
getenv()
/setenv()
/putenv()
.Au démarrage, ils créent des variables shell pour chaque variable d'environnement. Ceux-ci seront stockés dans des structures internes qui ont besoin de transporter d'autres informations comme si la variable est exportée, en lecture seule ... Ils ne peuvent pas utiliser les libc
environ
pour cela.De même, et pour cette raison, ils ne seront pas utiliser
execlp()
,execvp()
pour exécuter des commandes mais appeler l'execve()
appel système directement, le calcul duenvp[]
tableau en fonction de la liste de leurs variables exportées.Donc, dans votre
gdb
, vous devez ajouter une entrée à cette table interne de variables de shell, ou éventuellement appeler la bonne fonction qui lui ferait interpréter unexport VAR=value
code pour mettre à jour cette table par elle-même.Quant à savoir pourquoi vous voyez une différence entre
bash
etzsh
lorsque vous appelezsetenv()
dansgdb
, je pense que ce que vous appelezsetenv()
avant que le shell initialise, par exemple lors de l' entréemain()
.Vous remarquerez que
bash
l «main()
estint main(int argc, char* argv[], char* envp[])
(et lesbash
cartes des variables de celles env VARsenvp[]
) , alors quezsh
l » estint main(int argc, char* argv[])
etzsh
obtient les variables de laenviron
place.setenv()
modifieenviron
mais ne peut pas modifierenvp[]
sur place (lecture seule sur plusieurs systèmes ainsi que les chaînes vers lesquelles pointent ces pointeurs).Dans tous les cas, après la lecture du shell
environ
au démarrage, l'utilisationsetenv()
serait inefficace car le shell n'utilise plusenviron
(ougetenv()
) par la suite.la source