あなたは孫について話しているので、あなたは明らかに子をカスケード的にスポーンしています。これは、パイプを実装するための可能な方法です。
ただし、パイプからの戻り値(ターミナルで実行するときに取得する値echo $?
)は、右端のコマンドから返される値であることに注意してください。
これは、このカスケード実装では、子を右から左にスポーンする必要があることを意味します。あなたはその戻り値を失いたくありません。
ここで、単純化のために組み込みコマンドについてのみ話していると仮定すると(fork()およびexecve()への追加の呼び出しは行われません)、興味深い事実は、「zsh」などの一部のシェルでは、右端のコマンドはそうではないということです。フォークさえ。次のような単純なパイプコマンドでそれを確認できます。
export stack=OVERFLOW | export overflow=STACK
次にコマンドを使用するenv
と、環境変数でのoverflow=STACKの永続性を理解できます。これは、右端のコマンドがサブシェルで実行されなかったことを示していますが、実行されましたexport stack=OVERFLOW
。
注:これは、「sh」のようなシェルには当てはまりません。
次に、基本的なパイプコマンドを使用して、このカスケード実装の可能なロジックを示します。
cat /dev/random | head
注:これcat /dev/random
はおそらく終了しないコマンドですが、コマンドhead
が。によって出力された最初の行の読み取りを完了するとすぐに停止しcat /dev/random
ます。これは、実行時にstdinが閉じられ、壊れたパイプへの書き込みが原因head
でコマンドが中止されるためです。cat /dev/random
論理:
親プロセス(シェル)は、実行するパイプがあることを確認します。次に、2つのプロセスをフォークします。親はシェルに留まり、子が戻るのを待ち、返された値を保存します。
第1世代の子のコンテキストでは、(パイプの右端のコマンドを実行しようとしています)コマンドが最後のコマンドではないことがわかり、再びfork()します(私が「カスケード実装」と呼んでいます)。フォークが完了したので、親プロセスは最初にそのタスク(head -1
)を実行し、次にstdinとstdoutを閉じてから、子を待ちます()。これは、最初にstdinとstdoutを閉じてから、wait()を呼び出すことが非常に重要です。stdinで読み取る場合、stdoutを閉じると、EOFが親に送信されます。stdinを閉じると、パイプに書き込もうとしている孫が「壊れたパイプ」エラーで中止されることを確認します。
孫のコンテキストでは、パイプの最後のコマンドであることがわかり、コマンドを実行してその値を返します(stdinとstdoutを閉じます)。