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"
実行可能値を出力します。これは、実行可能ファイルがコマンドを入力する場所とは「異なる環境」で実行されるためですか?
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を使用すると、親プロセスからコピーした環境ではなく、指定した環境でプログラムを実行できます。]