Bashがサブシェルを作成し、関連するスコープの問題を管理する方法を理解するのが困難です。誰かがこの問題に対する私の考えを一致させることができることを願っています。
私が最初に理解していないのは、変数がサブシェルで処理される方法です。 eXportフラグがオンでない場合、変数は継承されないと思います。ただし、グループ化によって作成されたサブシェルの場合はそうではありません。
$ n=3
$ ( pstree $$ ; echo $n )
bash---bash---pstree
3
対照的に、サブシェルを手動で作成すると、すべてが期待どおりに機能します。
$ export ppid=$$
$ bash
$ pstree $ppid
bash---bash---pstree
$ echo $n
さらに、一部のグループ化は実際にはサブシェルを生成しません。
( pstree $$ )
bash---pstree
実際に使用してはならないいくつかのグループは次のとおりです。
$ pstree $$ &
[1] 1685
$ bash---pstree
{ pstree $$; } &
[1] 1687
$ bash---bash---pstree
追跡する特別なケースが多いので、これは少し混乱しているようです。そしてそれはさらに混乱します。プロセスの交換を検討してください。
$ cat <(pstree $$)
bash-+-bash---pstree
`-cat
私が理解しているように、bashは子プロセスでcatを実行して読み取ることができるFIFOを提供します。その後、サブシェルをフォークし、FIFOのもう一方の端を提供します。サブシェルはpstreeを実行します。
さて、次のことを考えてみましょう。
$ pstree $$ > >(cat) # There is some non determinism involved, output may be different
bash---pstree---bash---cat
#or sometimes
bash---pstree---bash
ここでbashは何か違うことをしているようです。これはサブシェルをフォークし、サブシェルは別のサブシェルをフォークします: bash---bash(1)---bash(2)
bash(1)(FIFOの書き込み終了を取得)はpstreeを実行し、bash(2)(FIFOの書き込み終了を取得)は子プロセスでcatを実行します。
したがって、最初のケースでは、サブプロセスはプライマリシェルのサブシェルによって実行されます。 2番目は、メインコマンドのシェルサブプロセスによって実行されます。
2番目のケースは、catが作成される前にpstreeを実行できるためです。
ベストアンサー1
私はそれらのほとんどを扱おうとします。
サブシェルを実行すると()
、$()
:<()
bashが呼び出されますfork()
。これにより、新しいサブプロセスが作成されます。まったく同じを除いて親としてpid
、ppid
およびフォークの戻り値(0は子を意味し、正のpid、子は親を意味し、負の数はエラーを意味 - 子が生成されないことを意味します)。したがって、サブシェルは同じ状態/同じ変数を持ちます。
bashを呼び出すと、シェルが呼び出してfork()
から呼び出しますexec("bash")
(実際にはバリアントの1つ)。これにより、複製されたbashが新しいイメージに置き換えられ、最初から実行されます。したがって、変数が消去され、構成ファイルが再度読み取られます。
.Bashを使用すると、バックグラウンドプロセスを&
呼び出すことができます。fork()
必要以上にフォークされたように見えますが、フォークされたbashが管理作業を支援するために使用されている可能性があります。 (ポーキングが安くない理由)
最後の場合pstree $$ > >(cat)
。 (この問題を解決するのに時間がかかりました。):
Bashはいつものように新しいプロセスを実行します。 execを呼び出す前に、stdin / out / err(この場合はstdoutのみ)をリダイレクトする必要があります。これを行うにはcat
サブシェルで実行する必要があるため、そうなります。今cat
新しいカーニバルの子供たち。新しいカーニバルは古い子供です。次の新しいバスが呼び出されexec
ますpstree
。