
パイプを介してbashコマンドを接続すると、象徴的なことが起こりますか、それともすべて計算 - 通過 - 計算 - 通過ですか?
たとえば、head t.txt -n 5 | tail -n 2
計算head t.txt -n 5
し、tail -n 2
実行します。それとも最初にシェルに3〜5行を読み込むように指示する抽象化はありますか?おそらくこの例では違いはないようですが、他の場合は違いがあるようです。
答え1
シェルはpipe(2)
システムコールを使用して、2つのファイル記述子を持つカーネルに制限されたバッファを生成します。 1つはプロセスがバッファに書き込むことを可能にし、もう1つはプロセスがバッファから読み取ることを可能にします。
簡単なケースを考えてみましょう:
$ p1 | p2
この場合、概念的にはシェルは上記のパイプをfork()
作成し、子は標準出力ストリームをパイプの書き込みの終わりに接続してから子exec()
sを接続しますp1
。次に、シェルはfork()
再びsで、子は標準入力ストリームをパイプの読み取り端に接続してから子exec()
sに接続しますp2
。 (私は言った概念的にシェルは異なる順序で操作を実行できますが、アイデアは同じです。 )
その当時はp1
とp2
同時に実行中でした。 p1
パイプに書き込まれ、カーネルは書き込まれたデータをバッファにコピーします。 p2
パイプから読み取られ、カーネルはバッファから読み取られたデータをコピーします。パイプがいっぱいになると、カーネルはパイプから何かを読み取るまでp1
呼び出しをブロックし、いくつかのスペースを解放します。パイプが空の場合、カーネルはパイプにさらにデータが書き込まれるまで呼び出しをブロックします。write()
p2
p2
read()
p1
答え2
推奨されている2つのモデルのうち、計算されたパス - 計算されたパスが最も近いです。シェルは単なる接続プロセスです。彼らが何をしているのか分かりません。
とは別に、実行順序は未定義です。彼らは実際に同時に実行されます。ただし、左側が最初にバイトを出力し、右側がバイトを入力する必要があります。データは左から右に流れます。データは最初のコマンドから標準出力に流れ、次のプロセスの標準入力に移動し、そこで処理され、標準出力から出て別のプロセスにパイプすることができます。
リダイレクトなどを使用しないか、>
ファイル<
から読み取らない。それでは、次のようになります。
┌───────────┐ ┌───────────┐ ┌─────────────┐
Terminal⇨│Process one│⇨│Process two│⇨│Process Three│⇨Terminal
└───────────┘ └───────────┘ └─────────────┘