「フォーク」、サブプロセス、および「サブシェル」情報

「フォーク」、サブプロセス、および「サブシェル」情報

この記事は基本的に記事の後続の記事です。前の質問私のもの。

forkこの質問に答えて、私は「サブシェル」の全体的な概念をよく理解していなかっただけでなく、より一般的に-ingとサブプロセス間の関係を理解し​​ていないことに気づきました。

私はプロセスがXaを実行するとfork新しいY生成されたプロセスの親プロセスはですがX、この質問に対する回答によると、

[a]サブシェルはまったく新しいプロセスではなく、既存のプロセスのフォークです。

ここで意味するのは、「ポーキング」が「完全に新しいプロセス」ではないか、発生しないことです。

私は今混乱しています。実際、私の混乱を直接解決する一貫した質問をするのはとても混乱しています。

しかし、間接的に実現できる質問を投げることはできます。

sourceによると、新しいインスタンスが起動するたびにインポートされるため、zshall(1)$ZDOTDIR/.zshenv全くzsh新しい[zsh]プロセス」を生成するコマンドは無限回帰を引き起こします。$ZDOTDIR/.zshenv一方、ファイルに次の行のいずれかを含める$ZDOTDIR/.zshenvいいえ無限回帰につながります。

echo $(date; printenv; echo $$) > /dev/null    #1
(date; printenv; echo $$)                      #2

上記のメカニズムで無限回帰を実行する唯一の方法は、ファイルに次の1$ZDOTDIR/.zshenv行を含めることです。

$SHELL -c 'date; printenv; echo $$'            #3

私の質問は次のとおりです

  1. #1上記のフラグ付きコマンドとアカウント#2にフラグを付ける動作の違い#3は何ですか?

  2. で生成されたシェルを「サブシェル」と#1呼ぶ場合#2、 を呼び出して生成されたシェルに似たシェルは何ですか#3

  3. Unixプロセスの「理論」(より良い言葉がない)の点で、上記の経験的/逸話的な結果を合理化(および一般化)することは可能ですか?

最後の質問の動機は、次のことを決定できることです。リードタイム(つまり、実験に頼らない)どのような命令が含まれると、無限回帰につながる可能性がありますか$ZDOTDIR/.zshenv


1位のさまざまな例で使用したコマンドの具体的な順序date; printenv; echo $$それほど重要ではありません。それは私の「実験」の結果を説明するのに役立つ出力を提供するコマンドです。 (しかし、私は次の理由でこれらのシーケンスに複数のコマンドを含めたいと思います。ここ.)

ベストアンサー1

zshall(1)によると、zshの新しいインスタンスが起動されるたびに$ ZDOTDIR / .zshenvが取得されます。

「スタート」という言葉に集中すれば、より良くなるでしょう。この機能はfork()別のプロセスを作成することです現在プロセスがある場所から始める。既存のプロセスを複製し、唯一の違いは戻り値ですfork。ドキュメントでは、「スタート」を使用して最初からプログラムを起動するという意味で使用します。

例#3が実行され、$SHELL -c 'date; printenv; echo $$'まったく新しいプロセスが最初から始まります。通常の起動動作が発生します。たとえばbash -c ' ... '、別のシェルを交換してこれを説明できますzsh -c ' ... '。ここではシェルを使用することに特別なことはありません$SHELL

例#1と#2はサブシェルを実行します。自分でシェルを実行しfork、その子プロセス内でコマンドを実行し、子プロセスが完了したら独自のコマンドを実行し続けます。


あなたの質問#1に対する答えは次のとおりです。例3は最初からまったく新しいシェルを実行し、他の2つはサブシェルを実行します。起動アクションにはロードが含まれます.zshenv

このファイルは(他のファイルとは異なり)インタラクティブシェルと非インタラクティブシェルの両方にロードされるため、この動作の理由は混乱の原因である可能性があると具体的に説明されています。


質問#2の場合:

#1と#2で生成されたシェルを「サブシェル」とすると、#3と同様に生成されたシェルは「サブシェル」と呼ばれますか?

名前が欲しいなら「サブシェル」と呼ぶことができますが、実際には何もありません。同じシェルでも、別のシェルでも、シェルで開始された他のプロセスと変わりませんcat


質問#3の場合:

Unixプロセスの「理論」(より良い言葉がない)の点で、上記の経験的/逸話的な結果を合理化(および一般化)することは可能ですか?

fork新しいPIDを持つ新しいプロセスが作成され、プロセスが中断された時点から並列に実行されます。exec現在実行中のコードをどこかから読み込まれた新しいプログラムに置き換えて、最初からやり直してください。新しいプログラムを作成するときは、最初に生成してからサブルーチンforkからexecプログラムを生成します。これは、シェルの内側または外側のどちらでもプロセスに適用される基本理論です。

サブシェルはforksで、実行されるすべての非組み込みコマンドはおよびforkですexec


拡張は$$親シェルのPIDです。POSIX互換シェルからそのため、期待した結果が得られない場合があります。また、zshはとにかくサブシェルの実行を積極的に最適化し、通常は最後のコマンドになるか、またはサブシェルなしでexecすべてのコマンドが安全である場合、サブシェルをまったく生成しません。

直観をテストするのに役立つコマンドは次のとおりです。

strace -e trace=process -f $SHELL -c ' ... '

...これにより、新しいシェルで実行されるコマンドのすべてのプロセス関連イベント(他のイベントを除く)が標準エラーで印刷されます。新しいプロセスで何が実行されていないのか、execそれが発生する場所を確認できます。

便利なもう1つのコマンドは、pstree -h現在のプロセスの親プロセスツリーを印刷して強調表示することです。出力にレイヤ数を表示できます。

おすすめ記事