我对设置一个外壳实例与另一个外壳实例的环境变量感兴趣。所以我决定做一些研究。阅读了许多与此有关的问题后,我决定对其进行测试。
我生成了两个外壳A和B(PID 420),它们都在运行zsh
。从外壳程序AI运行以下命令。
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
从外壳B运行时,env
我可以看到变量FOO确实设置为bar值。这使我认为FOO已在shell B的环境中成功初始化。但是,如果我尝试打印FOO,则会出现一个空行,表明未设置FOO。对我来说,这里似乎有矛盾。
这已在我自己的Arch GNU / Linux系统和Ubuntu VM上进行了测试。我还在bash
变量甚至未在env中显示的地方对此进行了测试。尽管这让我感到失望,但如果shell在生成时缓存其环境的副本并仅使用它(在链接的问题之一中建议),则是有意义的。这仍然不能回答为什么zsh
可以看到变量。
为什么输出为echo $FOO
空?
编辑
输入评论后,我决定进行更多测试。结果可以在下表中看到。第一列是FOO
注入变量的外壳。第一行包含该命令的输出,可以在其下面看到。FOO
使用:注入变量sudo gdb -p 420 -batch -ex 'call setenv("FOO", "bar", 1)'
。zsh:专用的命令zsh -c '...'
也已使用bash进行了测试。结果是相同的,为简洁起见,省略了它们的输出。
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 |
以上似乎暗示结果与分布无关。这并不能告诉我更多,zsh
并且可以bash
不同地处理变量设置。此外,export FOO
在这种情况下,取决于外壳,其行为也非常不同。希望这些测试可以使别人清楚一些。
env
)会看到修改后的环境。
zsh
在GDB中为其设置环境变量不会使它作为shell变量可见,但会导致将其传递给子进程(如你观察到的),同时设置一个bash
不让它作为一个shell变量可见但没有导致它要在子进程过去了!看起来zsh和bash使用不同的策略来管理变量,zsh跟踪非环境变量,并且bash将其所有内容存储在其环境中,并在启动(非subshell)子级时对其进行了消毒。
export FOO
的bash
?
zsh -c 'echo $FOO'
改为执行(使用单引号!)会发生什么?那你看得到吗?