web-dev-qa-db-ja.com

Bashから実行されるプロセスは「サブシェル」で実行されますか?

Bashシェルから実行可能ファイル(a.outなど)を実行すると、その実行可能ファイルはある種の「サブ」シェルで実行されますか?つまり、入力しているシェルとは異なりますか?

例を挙げて質問を説明してみます。次のプログラムは、環境変数の値を取得して出力し、それを変更してから、再取得して再度出力します。

#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
StoneThrow

Unixでは、各processに環境の独自の独立したコピーがあります。プロセスは、親プロセスの環境をコピーすることにより、(fork()を介して)作成されたときに初期環境を取得します。

したがって、a.outを呼び出す前にシェルの環境に変数を追加すると、a.outにその変数が表示されます(a.outは、その変数を含むシェルの環境のコピーを受け取ったため)。

A.outが環境を変更すると、シェルではなくa.outの環境が変更されます。 a.outが別のプログラムを呼び出す場合(たとえば、system()を使用する場合)、そのプログラムはa.outの環境のコピーを取得するため、変更された環境を認識します。

A.outが終了すると、その環境変数は破棄されます。もちろん、子プロセスが実行されていた場合でも、そのコピーは(終了するまで)保持されます。

A.outの実行中にシェルで環境を変更した場合(例:バックグラウンドで:a.out &)の場合、a.outは変更を認識しません。環境はプロセスの作成時にのみコピーされます。

[これが典型的な方法であることに注意してください。 execve syscallを使用すると、親プロセスからコピーした環境ではなく、指定した環境でプログラムを実行できます。]

3
derobert