Bash

從 Bash 執行的程序是否在“子 shell”中執行?

  • December 16, 2018

當我從 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呼叫允許您使用您指定的環境執行程序,而不是從父程序複製的環境。]

引用自:https://unix.stackexchange.com/questions/426203