web-dev-qa-db-ja.com

パイプコマンドを実行するとき、Linuxユーティリティは賢いですか?

ターミナルでいくつかのコマンドを実行していたところ、パイプコマンドを実行するときにUnix/Linuxはショートカットを使用するのでしょうか?

たとえば、100万行のファイルがあり、その最初の10行にhello worldが含まれているとします。コマンドgrep "hello world" file | headを実行すると、最初のコマンドは10行が見つかるとすぐに停止しますか、それともファイル全体を最初に検索し続けますか?

23
DisgruntledGoat

ある種。シェルは、実行しているコマンドが何を実行するかを認識していません。一方の出力をもう一方の入力に接続するだけです。

grepが「helloworld」という10行を超える行を見つけた場合、headには必要な10行すべてが含まれ、パイプを閉じます。これにより、grepがSIGPIPEで強制終了されるため、非常に大きなファイルのスキャンを続行する必要はありません。

30
psusi

プログラムがパイプに書き込もうとし、そのパイプから読み取るプロセスがない場合、ライタープログラムは [〜#〜] sigpipe [〜#〜] シグナルを受信します。プログラムがSIGPIPEを受信したときのデフォルトのアクションは、プログラムを終了することです。プログラムはSIGPIPEシグナルを無視することを選択できます。その場合、書き込みはエラー(EPIPE)を返します。

あなたの例では、これが何が起こるかのタイムラインです:

  • grepコマンドとheadコマンドは並行して起動します。
  • grepは入力を読み取り、処理を開始します。
  • ある時点で、grepは出力の最初のチャンクを生成します。
  • headはその最初のチャンクを読み取り、書き込みます。
  • 最初の10回の一致の後に十分な行があると仮定すると(そうでない場合、grepが最初に終了する可能性があります)、最終的にheadは必要な行数を出力します。この時点で、headが終了します。
  • grepプロセスとheadプロセスの相対速度によっては、grepがデータを蓄積し、まだ印刷していない場合があります。 headが終了するとき、grepは入力を読み取っている、または内部処理を行っている可能性があります。その場合、引き続き処理が行われます。
  • 間もなくgrepは処理されたデータを書き出します。その時点で、それはSIGPIPEを受け取り、死にます。

grepは、厳密に必要な入力よりも少し多くの入力を処理する可能性がありますが、通常は数キロバイトしか処理しません。

  • headは通常、数キロバイトのチャンクを読み込みます(これは、バイトごとにreadシステムコールを発行するよりも効率的であるためです。この動作はバッファリングと呼ばれます)。したがって、後の最後のチャンクの残りは必要な最後の行は破棄されます。
  • パイプにはカーネルによって管理される関連バッファー(多くの場合512バイト)があるため、転送中のデータが存在する可能性があります。このデータは破棄されます。
  • grepは、出力チャンクになる準備ができているデータを蓄積している可能性があります(再度バッファリングします)。出力バッファをフラッシュしようとすると、SIGPIPEを受け取ります。

全体として、システムは、フィルタリングユーティリティが自然に効率的に動作するように正確に設計されています。出力チャネルが停止したときに続行する必要があるプログラムは、SIGPIPE信号を無視する手順を実行する必要があります。

パイプラインは次のように機能します。最初に最初のコマンドを実行し、次に2番目のコマンドを実行します。

つまり、A|B与えられたコマンドである。次に、AまたはBのどちらが最初に開始するかは不明です。複数のCPUがある場合、それらはまったく同時に起動する可能性があります。パイプは、未定義ですが有限量のデータを保持できます。

Bがパイプから読み取ろうとしたが、利用可能なデータがない場合、Bはデータが到着するまで待機します。 Bがディスクから読み取っていた場合、Bでも同じ問題が発生する可能性があり、ディスクの読み取りが完了するまで待機する必要があります。より近い例えは、キーボードからの読み取りです。そこで、Bはユーザーが入力するのを待つ必要があります。ただし、これらすべての場合において、Bは「読み取り」操作を開始しており、終了するまで待機する必要があります。しかし、BAの部分的な出力のみを必要とするようなコマンドである場合、Bsの入力レベルに達した特定のポイントの後、Aはによって強制終了されます。 SIGPIPE

Aがパイプに書き込もうとし、パイプがいっぱいになった場合、Aはパイプ内の空きができるまで待つ必要があります。 Aは、端末に書き込んでいる場合にも同じ問題が発生する可能性があります。端末にはフロー制御があり、データのペースを調整できます。いずれにせよ、Aに対して、「書き込み」操作を開始し、書き込み操作が終了するまで待機します。

ABはコプロセスとして動作しますが、すべてのコプロセスがパイプと通信するわけではありません。どちらも他方を完全に制御することはできません。

3
harish.venkat

grepはパイプを直接制御しません(データを受信するだけです)。また、パイプはgrepを直接制御しません(データを送信するだけです)。

grepまたは他のプログラムが行うことは、完全にそのプログラムの内部ロジック次第です。コマンドラインオプションを介してgrepに早期にexit-when-foundを作成するように指示すると、そうなります。そうでない場合は、ファイルの最後に移動してパターンを探します。 ..

同様に、ターミナルはgrepの内部動作とShellの配管動作から完全に切り離されています...ターミナルは基本的に単なる発射台であり、出力ディスプレイです...

1
Peter.O