Learning Bash Bookでは、サブシェルは環境変数やファイル記述子などを継承し、エクスポートしない変数は継承しないと述べています。
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
私が知る限り、シェルはfor()
とforの2つのサブシェルを生成します./file
。しかし、この()
場合、サブシェルがvar
変数をエクスポートしていないにもかかわらず、変数を認識し、その./file
場合は認識しません。
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
strace
私はこれがどのように起こったのかを理解しようとしましたが、驚くべきことに、bashはレプリケーションシステムコールに同じ引数を使用することを発見しました。つまり、これはフォークされたプロセスを意味し、親プロセス()
と./file
同じプロセスアドレス空間を持つ必要があります。()
この場合、変数はサブシェルに表示されますが、レプリケーション./file
syscallに基づく同じパラメータにもかかわらず同じ状況は発生しませんか?
ベストアンサー1
あなたやこの本は、サブシェルをシェルであるサブプロセスと混同しています。
一部のシェル構成はシェルを生成します。分岐子プロセスLinuxでは、これはfork
ログで観察されるより一般的なシステムコールの特別なケースです。子プロセスはシェルスクリプトの一部を実行します。子プロセスが呼び出されます。clone
strace
サブシェル。最も簡単な設定は次のとおりですcommand1 &
。command1
子シェルで実行し、後続のコマンドは親シェルで実行されます。サブシェルを生成するための他の構成には、コマンドの置き換えと$(command2)
パイプcommand3 | command4
(ほとんどのシェルcommand3
ではサブシェルで実行されますが、command4
kshまたはzshでは実行されません)が含まれます。
サブシェルは親プロセスのコピーなので、同じ環境変数だけでなく、変数(元のシェル$$
プロセスのプロセスIDを含む)、関数、エイリアス、オプションなどの内部定義も同じです。サブシェルでコードを実行する前に、bashは変数をBASHPID
サブプロセスのプロセスIDに設定します。
これを実行すると外部コマンドが実行されます./file
。まず、シェルは子プロセスをフォークしてから、子プロセスをフォークします。実装する(execve
システムコールを介して)実行可能ファイル./file
。子プロセスは、親プロセスのプロセス属性(環境、現在のディレクトリなど)を継承します。アプリケーションの内部側面は通話中に失われますexecve
。エクスポートされていない変数、関数などはカーネルに未知のbashの概念であり、bashが他のプログラムを実行すると失われます。他のプログラムがbashスクリプトであっても、新しいbashインスタンスによって実行されます。これは、親プロセスもbashインスタンスであるという事実を知らないか気にしません。したがって、シェル変数(エクスポートされていない変数)は生き残ることができませんexecve
。