Bash
從 Bash 執行的程序是否在“子 shell”中執行?
當我從 Bash shell 執行執行檔(如 a.out)時,該執行檔是否在某種“子”shell 中執行,即與我輸入的 shell 不同?
我將嘗試用一個例子來說明我的問題。以下程序獲取並列印環境變數的值,對其進行更改,然後重新獲取並再次列印:
#include <iostream> #include <string> #include <cstdlib> int main( int argc, char* argv[] ) { std::string str( getenv( "FOO" ) ); std::cout << str << std::endl; setenv( "FOO", "bar", 1 ); str = getenv( "FOO" ); std::cout << str << std::endl; return 0; }
現在,當我在 Bash 提示符下執行以下命令時,請注意輸出:
>unset FOO && export FOO=foo && printf "$FOO\n" && ./a.out && printf "$FOO\n" foo foo bar foo > >unset FOO && export FOO=baz && printf "$FOO\n" && ./a.out && printf "$FOO\n" baz baz bar baz
所以我正在導出
FOO
,所以它可以從執行檔中獲取 - 我明白這一點。並且執行檔的輸出顯示正在更改的環境變數。但最終
printf "$FOO\n"
列印出可預執行的值。這是因為執行檔在與我鍵入命令的“不同環境”中執行嗎?
在 Unix 上,每個程序都有自己獨立的環境副本。
fork()
程序在創建時(通過)通過複製父程序的環境來獲取其初始環境。因此,如果您在呼叫 a.out 之前將變數添加到 shell 的環境中,a.out 會看到它(因為 a.out 收到了包含該變數的 shell 環境的副本)。
如果 a.out 改變了環境,那就改變了 a.out 的環境——而不是 shell 的。如果 a.out 要呼叫另一個程序(例如,使用
system()
),那麼該程序將看到更改的環境,因為它會得到 a.out 環境的副本。當 a.out 退出時,其環境變數被銷毀;當然,如果一個子程序正在執行,它仍然會保留它的副本(直到它退出)。
如果您在 shell 中修改環境,而 a.out 仍在執行(例如,在後台
a.out &
:),那麼 a.out 將看不到更改:環境僅在程序創建時被複製。[注意這是典型的方式;系統
execve
呼叫允許您使用您指定的環境執行程序,而不是從父程序複製的環境。]