「grep -q」が入力ファイル全体を消費するのはなぜですか?

「grep -q」が入力ファイル全体を消費するのはなぜですか?

次の入力ファイルを検討してください。

1
2
3
4

走る

{ grep -q 2; cat; } < infile

何も印刷されません。印刷したい

3
4

これを次のように変更すると、期待した結果が得られます。

{ sed -n 2q; cat; } < infile

最初のコマンドが期待した出力を印刷しないのはなぜですか?
これは検索可能な入力ファイルで、次に基づいています。基準下にオプション:

-q
      Quiet. Nothing shall be written to the standard output, regardless of 
      matching lines. Exit with zero status if an input line is selected.

さらに下に、アプリケーションの使い方(強調):

この-qオプションを使用すると、ファイルセットにパターン(または文字列)が存在するかどうかを簡単に確認できます。複数のファイルを検索するときのパフォーマンス向上を提供します(最初の一致が見つかったら終了できるからです。)[...]

今、同じ基準で(紹介する、下に入力ファイル)

標準ユーティリティが検索可能な入力ファイルを読み取り、ファイルの終わりに達する前にエラーなしで終了した場合、ユーティリティーは、オープン・ファイル記述のファイル・オフセットが、ユーティリティーが処理した最後のバイトの後に正しく配置されていることを確認する必要があります。[...]

tail -n +2 file
(sed -n 1q; cat) < file
...

2番目のコマンドは、ファイルを検索できる場合にのみ最初のコマンドと同じです。


grep -q完全なファイルを使用するのはなぜですか?


gnu grepそれが大切だったら(でも先行は達成するのが難しいOpenBSDでも同じことが起こることを確認しました)

答え1

grep早く停止しますが、入力をバッファリングするため、テストが短すぎます(例:検索できないため、テストが不完全であることを知っています)。

seq 1 10000 | (grep -q 2; cat)

私のシステムでは6776で始まります。その試合32KiBバッファGNU grepはデフォルトで以下を使用します。

seq 1 6775 | wc

出力

   6775    6775   32768

POSIXでは、パフォーマンスの向上のみに言及しています。

複数のファイルを検索するとき

単一のファイルを部分的に読み取るため、パフォーマンスの向上は期待できません。

答え2

grepこれは、バッファリングによって作業速度が速くなるためです。一部のツールは、要求された数の文字を読むことができるように特別に設計されています。そのうちの1つは次のとおりですexpect

{ expect -c "log_user 0; expect 2"; cat; } < infile

これを試すことができるシステムはありませんが、expect予想される文字列()に会うまですべてを食べてから終了し、残りの2入力は残すと思いますcat

答え3

sedとgrepを混同しています。

sedコマンドの場合、2行目にある場合、オプションは自動的に実行されることを意味します。つまり、-2q現在の繰り返しを終了するという意味なので、2行目以降のすべての行を取得することになります。-n

grep コマンドは、デフォルトで一致するすべての行を印刷するために実行されます。ただし、この-qオプションは標準出力に何も印刷しないことを意味します。したがって、入力に「2」が含まれている場合、終了値は「成功」、そうでなければ「失敗」です。これが何であるかは、オペレーティングシステムとシェルによって異なります。したがって、通常、grepプロセスの終了値を調べて、行が一致するかどうかを確認できます。これは、入力にテストに特定の値が含まれているかどうかを知りたいパイプラインで役立ちます。例えば

if grep -q 'crash' <somelog.log ; then report_crash_via_email ; fi

この場合、実際に一致するすべての行を見ることには興味がなく、少なくとも1つでもあるかどうかにのみ関心があります。その後、プロセスreport_crash_via_email/関数はファイルを閉じて再度開くことも、そうでない場合もあります。

「2」文字を見つけた後にgrepプロセスを停止するには(デフォルトではそうではありません)、すべての行を調べて一致するものがあるかどうかを確認します。そうするように指示する必要があります。コマンドラインスイッチはです-m <value>。したがって、あなたの場合はgrep -q -m1 2

関連情報