rlf*_*rlf 9 linux shell bash zsh environment-variables
我对从另一个 shell 实例设置一个 shell 实例的环境变量感兴趣。所以我决定做一些研究。在阅读了一些关于此的问题后,我决定对其进行测试。
我生成了两个 shell A 和 B(PID 420),都运行zsh. 从 shell AI 运行以下内容。
sudo gdb -p 420
(gdb) call setenv("FOO", "bar", 1)
(gdb) detach
Run Code Online (Sandbox Code Playgroud)
从 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 进行了测试。结果是相同的,为简洁起见省略了它们的输出。
| | 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 |
Run Code Online (Sandbox Code Playgroud)
| | 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 |
Run Code Online (Sandbox Code Playgroud)
以上似乎暗示结果与分布无关。这并没有告诉我更多,zsh并且bash以不同的方式处理变量的设置。此外,export FOO根据外壳,在此上下文中具有非常不同的行为。希望这些测试可以让其他人清楚一些。
大多数 shell 不使用getenv()// setenv()API putenv()。
启动时,他们为收到的每个环境变量创建 shell 变量。这些将存储在需要携带其他信息(例如变量是否导出、只读)的内部结构中……它们不能使用 libcenviron来实现这一点。
同样,出于这个原因,他们不会使用execlp(),execvp()来执行命令,而是execve()直接调用系统调用,envp[]根据导出的变量列表计算数组。
因此gdb,在您的 中,您需要向 shell 内部变量表添加一个条目,或者可能调用正确的函数,使其解释代码export VAR=value以自行更新该表。
至于为什么您在调用bash和时看到差异,我怀疑这是因为您在 shell 初始化之前调用,例如在输入 时。zshsetenv()gdbsetenv()main()
您会注意到bash's main()is int main(int argc, char* argv[], char* envp[])(并bash映射 中那些环境变量中的变量envp[]),而zsh's isint main(int argc, char* argv[])并zsh从中获取变量environ。setenv()确实修改environ但不能envp[]就地修改(在多个系统以及这些指针指向的字符串上只读)。
无论如何,在 shellenviron启动时读取后,使用setenv()将无效,因为 shell 此后不再使用environ(或getenv())。
| 归档时间: |
|
| 查看次数: |
1191 次 |
| 最近记录: |