从 Bash 运行的进程是否在“子 shell”中运行?

从 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"会打印预执行值。这是因为可执行文件在与我键入命令的“不同环境”中运行吗?

答案1

在 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调用允许您使用指定的环境执行程序,而不是从父进程复制的环境。]

相关内容