為什麼我不能列印在 env 的輸出中可以看到的變數?
我有興趣從另一個 shell 實例設置環境變數。所以我決定做一些研究。在閱讀了一些關於此的問題後,我決定對其進行測試。
我生成了兩個 shell A 和 B (PID 420),都在執行
zsh
. 從 shell AI 執行以下內容。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
變數甚至沒有出現在環境中的地方。雖然這對我來說令人失望,但如果 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
根據外殼,在這種情況下具有非常不同的行為。希望這些測試可以讓其他人明白一些事情。
大多數 shell 不使用
getenv()
// APIsetenv()
。putenv()
在啟動時,他們為收到的每個環境變數創建 shell 變數。這些將儲存在需要攜帶其他資訊的內部結構中,例如變數是否已導出,只讀……他們不能
environ
為此使用libc。同樣,出於這個原因,他們不會使用
execlp()
,execvp()
來執行命令,而是execve()
直接呼叫系統呼叫,envp[]
根據導出的變數列表計算數組。因此,在您的 中
gdb
,您需要向該 shell 內部變數表添加一個條目,或者可能呼叫正確的函式,使其解釋export VAR=value
程式碼以自行更新該表。至於為什麼您會在呼叫in
bash
和呼叫時看到差異,我懷疑這是因為您在 shell 初始化之前呼叫,例如在輸入zsh``setenv()``gdb``setenv()``main()
您會注意到
bash
’smain()
isint main(int argc, char* argv[], char* envp[])
(並bash
映射來自 env vars 中的變數envp[]
),而zsh
’s isint main(int argc, char* argv[])
並zsh
從中獲取變數environ
。setenv()
確實修改environ
但不能envp[]
就地修改(在幾個系統上以及這些指針指向的字元串上是只讀的)。在任何情況下,在 shell
environ
在啟動時讀取之後, usingsetenv()
將無效,因為 shell 之後不再使用environ
(或getenv()
)。