パイプコマンドを実行する場合、Linuxユーティリティはスマートですか?


23

ターミナルでいくつかのコマンドを実行していましたが、パイプコマンドを実行するときにUnix / Linuxがショートカットを取得しますか?

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


2
そのため、gnu grepには-m引数があります。
ポールトンブリン

3
端末はそれとは何の関係もありません。パイプコマンドはシェルによって管理されます。
キーストンプソン

@KeithThompsonは私の無知を許してくれます。専門用語はそれほどでもないので、ターミナル、シェル、またはコマンドラインと呼ぶべきかどうかはわかりませんでした。私の質問の編集を自由に提案してください:)
DisgruntledGoat

回答:


30

並べ替え。シェルは、実行中のコマンドが何をするのか分からず、一方の出力を他方の入力に接続するだけです。

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


2
だから、レース条件のために、grepはすでに11番目または12番目のパターンを読んでいたかもしれませんが、おそらく10万個ではないでしょうか?
ユーザー不明

3
これは、部分的には行の長さとパイプバッファーのサイズに依存しますが、簡単な答えは、grepは強制終了する前にある程度の余分なデータを読み取ることです。
dmckee

1
@userunknown、正確に。
-psusi

クール、私はそれが起こったことを知りませんでした。grep/dev/null
-Izkata

15

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

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

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

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

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

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


3

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

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

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

場合A試みは、パイプへの書き込みをし、パイプがいっぱいになる、A自由になるためにパイプでいくつかの部屋を待つ必要があります。A端末に書き込んでいた場合、同じ問題が発生する可能性があります。端末にはフロー制御があり、データのペースを調整できます。いずれにしても、to Aは、「書き込み」操作を開始し、書き込み操作が完了するまで待機します。

AそしてB全ての共処理はパイプに連通するが、共同プロセスとして動作しています。どちらも他方を完全に制御することはできません。


1
問題は、「Bがパイプの側面を閉じたときにAが何をするか」です。
enzotib

2
それは「壊れたパイプ」ではないでしょうか?
パトコスチャバ

1
プログラムが閉じたパイプとの間で読み書きを試みた場合(例:head終了)、プログラムでSIGPIPEシグナルが発生し、デフォルトの動作は終了します。
-Lekensteyn

これは質問にどのくらい正確に答えますか?psusiの答えはもっと短く、要点に近いようです
jw013

1

grepパイプを直接制御することはなく(データを受信するだけです)、パイプを直接制御grepすることはありません(データを送信するだけです)...

どのようなgrep他のプログラムがない、または、完全にアップしているプログラムの内部ロジックにあります。あなたが教えてくれた場合はgrep早期に行うために、コマンドラインオプションを経由していたときに出口を-、それは、それ以外の場合は、パターンを探して、ファイルの最後までの一気飲みますでしょう...

同様に、ターミナルはの内部動作grepshellのパイピングアクションから完全に切り離されています...ターミナルは基本的には起動パッドと出力ディスプレイにすぎません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.