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


23

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

1
2
3
4

ランニング

{ grep -q 2; cat; } < infile

何も印刷しません。私はそれが印刷されると期待しています

3
4

に変更すると、期待どおりの出力を得ることができます

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

最初のコマンドが期待される出力を印刷しないのはなぜですか?
これはシーク可能な入力ファイルであり、OPTIONS標準従っています。

-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オプションは、ファイルのグループにパターン(または文字列)が存在するかどうかを簡単に判断する手段を提供します。複数のファイルを検索する場合、パフォーマンスが向上します(最初に一致するものが見つかるとすぐに終了できるため)[...]

現在、同じ標準に従って(はじめにINPUT FILESの下)

標準ユーティリティがシーク可能な入力ファイルを読み取り、ファイルの終わりに達する前にエラーなしで終了する場合、ユーティリティは、開いているファイルの説明のファイルオフセットが、ユーティリティによって処理された最後のバイトを過ぎて適切に配置されるようにします [。 ..]

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

2番目のコマンドは、ファイルがシーク可能な場合にのみ最初のコマンドと同等です。


なぜgrep -qファイル全体を消費するのですか?


これはgnu grep重要な場合です(ただし、KusalanandaはOpenBSDでも同じことが起こることを確認したばかりです)


OpenBSD grepFreeGrepと呼ばれるもののフォークです。
クサラナナンダ

回答:


37

grep 早く停止しますが、入力がバッファリングされるため、テストが短すぎます(そして、はい、シークできないため、テストが不完全であることに気付きます)。

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

私のシステムでは6776から始まります。これは、GNU grepでデフォルトで使用される32KiBバッファーと一致します。

seq 1 6775 | wc

出力

   6775    6775   32768

POSIXはパフォーマンスの改善のみに言及していることに注意してください

複数のファイルを検索する場合

これは、単一のファイルを部分的に読み取ることによるパフォーマンスの向上に対する期待を設定しません。


2

これは明らかに、grep物事をスピードアップするためのバッファリングによるものです。要求された数だけ文字を読み取るように特別に設計されたツールがあります。それらの1つはexpect次のとおりです。

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

私はこれを試すシステムを持っていませんがexpect、期待される文字列(2)に遭遇するまですべてを食べ尽くしてから終了し、残りの入力をに残しますcat


1

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

sedコマンドの-2q場合、2行目で-nオプションが静かに機能しているので、2行目以降にすべての行が表示される場合、現在の反復を終了するように言っています。

grepコマンドはデフォルトで実行され、一致するすべての行を出力します-しかし、-qオプションはstdoutに何も出力しないと言います。そのため、入力に「2」が含まれる場合、終了値はSUCCESSになり、そうでない場合はFAILUREになります。それらが何であるかは、オペレーティングシステムとシェルによって異なります。そのため、通常、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


6
あなたの答えは、一般的な使用に役立つ情報ですgrepが、この質問は、より微妙で難解なものについて尋ねています。質問をあまりにも早く読んで、実際のクエリの動作を理解できないようです。また、GNU grep -q(POSIX仕様からの引用で許可されているように)使用すると検索を停止します。FWIW、あなたの質問を編集して、将来の投稿をどのようにフォーマットできるかを示しました。Stack Exchangeへようこそ。
アンソニーG-モニカの正義

とはいえ、@ user212377の答えは正しいです。この例でgrepは、ファイルに「2」が存在するかどうかを尋ねられています。その時点まではレコードのように動作せsed、レコードを消費せ、残りのレコードはさらなる処理のために残します。「2」が存在するか、存在しないことがわかるまで読み取り、ファイルを閉じ、結果を返します。
キースデイヴィス

grep実際、ファイル内に検索文字列が存在しない場合(ファイル全体を調べることでのみ証明可能)、「ファイル全体を消費する」だけです(バッファリングの考慮事項を無視します)。それ未満の場合、ファイルの読み取りは停止し、ファイルは閉じられ、SUCCESSが返されます。
キースデイヴィス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.