微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

linux – 为什么我不能打印我在env的输出中看到的变量?

我有兴趣从另一个shell实例设置环境变量.
所以我决定做一些研究.
在阅读了questionsnumberthis之后,我决定对其进行测试.

生成了两个shell A和B(PID 420),两个都运行zsh.
从shell A我跑了以下.

sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach

从shell B运行env时我可以看到变量FOO确实设置为bar值.
这让我觉得FOO已经在shell B的环境中成功初始化了.
但是,如果我尝试打印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处理变量设置更多的不同.
此外,导出FOO在此上下文中具有非常不同的行为,具体取决于shell.
希望这些测试可以让其他人明白.

解决方法:

大多数shell不使用getenv()/ setenv()/ putenv()API.

启动时,它们为每个环境变量创建shell变量.这些将存储在需要携带其他信息的内部结构中,例如变量是否被导出,只读……他们不能使用libc的环境.

同样,出于这个原因,他们不会使用execlp(),execvp()来执行命令,而是直接调用execve()系统调用,根据导出变量列表计算envp []数组.

因此,在您的gdb中,您需要向该shell内部变量表添加一个条目,或者可能调用正确的函数,使其解释导出VAR = value代码,以便它自己更新该表.

至于为什么在gdb中调用setenv()时看到bash和zsh之间的区别,我怀疑是因为你在shell初始化之前调用setenv(),例如在输入main()时.

您会注意到bash的main()是int main(int argc,char * argv [],char * envp [])(和bash映射envp []中那些env变量的变量)而zsh是int main(int argc, char * argv [])和zsh从environ获取变量. setenv()确实修改了environ但不能就地修改envp [](在几个系统上只读以及这些指针指向的字符串).

在任何情况下,在shell启动后读取环境后,使用setenv()将无效,因为shell之后不再使用environ(或getenv()).

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐