連続ストリームを「grep」する方法は?


729

grep連続ストリームで使用することは可能ですか?

私が言っているのは一種のtail -f <file>コマンドですが、grep私が興味を持っている行だけを保持するために出力を使用しています。

私は試しましたtail -f <file> | grep patternが、それが完了するのはgrep一度しか実行できないようtailです、つまり絶対に実行できないようです。


9
ファイルを生成するプログラムがその出力をフラッシュしていない可能性が高いです。
Steve-o

tail -f file動作します(新しい出力はリアルタイムで表示されます)
Matthieu Napoli


@リュックは確かに、それを考えていませんでした
Matthieu Napoli

入力ストリームに改行がない可能性がありますか?その場合、grepは続行されません。
リンチ

回答:


1327

grepBSD grep(FreeBSD、Mac OS Xなど)を使用する場合、のラインバッファリングモードをオンにします。

tail -f file | grep --line-buffered my_pattern

デフォルトでフラッシュするため(GNU grep(ほとんどのLinuxで使用))にこれを行う必要はありません(SmartOS、AIX、QNXなどの他のUnixライクではYMMV)。


3
@MichaelNiemandは、tail -Fファイルを使用できます。grep --line-buffered my_pattern
jcfrei

47
@MichaelGoldshteyn安心してください。人々がグーグル「grep line buffered」でこのページを見つけ、それが質問として提起されたものではないかもしれない問題を解決するので、人々はそれを賛成します。
Raineの

4
の出力をgrepしようとしてここに来ましたstrace。なし--line-bufferedでは機能しません。
sjas

5
@MichaelGoldshteyn(および彼のコメントの賛成者):私は常にでこの問題を抱えておりtail -f | grep--line-buffered私のためにそれを解決してくれました(Ubuntu 14.04では、GNU grepバージョン2.16)。「stdoutがttyである場合、ラインバッファリングを使用する」ロジックはどこに実装されていますか?でgit.savannah.gnu.org/cgit/grep.git/tree/src/grep.cline_buffered唯一の引数パーサによって設定されています。
Aasmund Eldhuset 2017年

8
@MichaelGoldshteyn私はBSD grepを使用してmacOSにいて--line-buffered、何も出力しません。しかし、テスト後、GNU grepはあなたが記述したことを実行しているように見えます。したがって、ほとんどのUnixと同様に、プラットフォームの実装に依存します。質問はプラットフォームを指定していないので、あなたの情報が虚偽であるように思われる- BSD grepのためのコードを見直し、GNU grepのそれを比較した後、行動は間違いなく--line-バッファリングオプションによって制御されています。デフォルトでは、GNU grepのみがフラッシュします。
リチャードウェイト2017年

119

ずっと使ってtail -f <file> | grep <pattern>います。

終了するまでではなく、grepがフラッシュするまで待機します(私はUbuntuを使用しています)。


4
これはかなり長く続く可能性があるので、焦らないようにしてください。
glglgl

おおよそどのくらいの時間がかかりますか?
Matthieu Napoli

@Matthieu:主にgrepの目的と、OSでのバッファーの大きさによって異なります。grepが数時間ごとに短い文字列にのみ一致する場合、最初のフラッシュの数日前になります。
tripleee 2011

13
Tailは出力バッファリングを使用しません-grepが使用します。
XzKto 2011

7
いいえ、出力がttyデバイスに送られる場合、grepは出力バッファリングを行いません。これは明らかにこの回答にあるためです。行バッファリングを行います!これは正解であり、受け入れられるべき答えです。詳細については、現在受け入れられている(間違った)回答に対する長いコメントを参照してください。
Michael Goldshteyn

67

あなたの問題は、grepが出力バッファリングを使用していることだと思います。試す

tail -f file | stdbuf -o0 grep my_pattern

grepの出力バッファリングモードをunbufferedに設定します。


7
これには、以外にも多くのコマンドに使用できるという利点がありますgrep
PeterV.Mørch12年

4
しかし、もっと遊んでみてわかったように、いくつかのコマンドはttyに接続されたときに出力をフラッシュするだけで、そのためにはunbufferexpect-devdebian のパッケージ内で)kingです。そのため、stdbufではなくunbufferを使用します。
ピーターV.モーチ

5
@Peter V.Mørchはい、そうです。stdbufができない場所でunbufferが機能することがあります。しかし、あなたは問題を理解するのではなく、常に問題を解決する「魔法の」プログラムを見つけようとしていると思います。仮想ttyの作成は無関係なタスクです。stdbufは私たちが望むものを正確に実行し(標準出力バッファーを設定して値を与える)、unbufferは私たちが望まない可能性のある多くの非表示のものを実行します(topstdbufおよびunbuffer との対話と比較してください)。そして、実際には「魔法の」解決策はありません。たとえば、バッファリングが失敗することもあります。たとえば、awkは異なるバッファ実装を使用します(stdbufも失敗します)。
XzKto

2
「しかし、問題を理解するのではなく、常に問題を解決する「魔法の」プログラムを見つけようとしていると思います。」-私はあなたが正しいと思います!;-)
PeterV.Mørch、2012

1
pixelbeat.org/programming/stdio_bufferingのstdbuf、 `unbuffer、およびstdioバッファリングに関する詳細情報
Tor Klingberg '27

13

ファイル全体(末尾だけでなく)で一致を検索し、座って新しい一致を待つ場合、これはうまく機能します。

tail -c +0 -f <file> | grep --line-buffered <pattern>

この-c +0フラグは、出力がファイルの先頭()から0バイト(-c)で始まること+を示しています。


12

ほとんどの場合、それは可能でtail -f /var/log/some.log |grep foo、問題なく機能します。

実行中のログファイルで複数のgrepsを使用する必要があり、出力が得られない場合は、次の--line-bufferedようにスイッチを中央の grep に固定する必要がある場合があります。

tail -f /var/log/some.log | grep --line-buffered foo | grep bar

7

あなたはこの答えを拡張と考えるかもしれません..通常私は使用しています

tail -F <fileName> | grep --line-buffered  <pattern> -A 3 -B 5

-Fは、ファイルを回転する場合に適しています(ファイルを回転すると、-fは正しく機能しません)

-Aおよび-Bは、パターンオカレンスの直前と直後の行を取得するのに役立ちます。これらのブロックは、破線のセパレータの間に表示されます。

しかし、私にとっては、次のことを好む

tail -F <file> | less

これは、ストリーミングされたログ内を検索する場合に非常に役立ちます。前後に行って深く見ます


4
grep -C 3 <pattern>、Nが同じ場合、-A <N>と-B <N>を置き換えます。
AKS 2017年

6

誰もが私の通常の目的にこれを提供するのを見ていませんでした:

less +F <file>
ctrl + c
/<search term>
<enter>
shift + f

私はこれを好みます。なぜならctrl + c、いつでもファイルを停止してナビゲートし、次にヒットshift + fするだけでライブのストリーミング検索に戻ることができるからです。


4

sedの方が適しています(ストリームエディター)

tail -n0 -f <file> | sed -n '/search string/p'

そして、特定の文字列が見つかったら、tailコマンドを終了したい場合は、次のようにします。

tail --pid=$(($BASHPID+1)) -n0 -f <file> | sed -n '/search string/{p; q}'

明らかにバシズム:$ BASHPIDはtailコマンドのプロセスIDです。sedコマンドはパイプの末尾の次にあるため、sedプロセスIDは$ BASHPID + 1になります。


1
システム($BASHPID+1)で開始された次のプロセスがあなたのものであるという仮定は多くの状況で誤りであり、これはおそらくOPが尋ねようとしていたバッファリングの問題を解決するためには何もしません。特に、ここで推奨sedするgrepことは、単に(疑わしい)好みの問題のようです。(それがあなたが配達しようとしているポイントp;qであるgrep -m 1なら、あなたは行動を得ることができます。)
tripleee

動作します。sedコマンドは準備ができるとすぐに各行を出力しますが、grepコマンド--line-bufferedはそうではありませんでした。私は心からマイナス1を理解していません
。– MUYベルギー'23

バッファリングがgrepの問題であることは、これまでに確立されています。sedを使用して行バッファリングを処理するために特別なアクションは必要ありません。これはデフォルトの動作であるため、単語ストリームに重点を置いています。そして確かに、$ BASHPID + 1が正しいpidになる保証はありませが、pidの割り当ては順次であり、パイプされたコマンドには直後にpidが割り当てられるため、それはまったくありそうです。
Christian Herr

1

はい、これは実際には問題なく動作します。GrepほとんどのUnixコマンドは、一度に1行ずつストリームを操作します。末尾から出てくる各行は分析され、一致する場合は渡されます。


2
それは実際には正しくありません。場合はgrep、パイプ・チェーンの最後のコマンドであるあなたが説明として、それが動作します。ただし、中央にある場合は、一度に約8kの出力をバッファリングします。
Mahmoud Al-Qudsi 2016

1

次の1つのコマンドでうまくいきます(Suse)。

mail-srv:/var/log # tail -f /var/log/mail.info |grep --line-buffered LOGIN  >> logins_to_mail

メールサービスへのログインの収集


-1

あなたは確かに成功しません

tail -f /var/log/foo.log |grep --line-buffered string2search

テールのエイリアスとして「colortail」を使用する場合。バッシュで

alias tail='colortail -n 30'

タイプエイリアスでこれが出力されるかどうかを確認できます colortail -n 30ます それからあなたはあなたの犯人を持っています:)

解決:

でエイリアスを削除する

unalias tail

このコマンドで「実際の」テールバイナリを使用していることを確認してください

type tail

これは次のようなものを出力するはずです:

tail is /usr/bin/tail

そして、あなたはあなたのコマンドを実行することができます

tail -f foo.log |grep --line-buffered something

幸運を。


-4

行バッファーオプションがない場合は、grepの代わりにawk(別の優れたbashユーティリティ)を使用してください。テールからデータを継続的にストリーミングします。

これがgrepの使い方です

tail -f <file> | grep pattern

これがawkの使い方です

tail -f <file> | awk '/pattern/{print $0}'

6
これは正しくありません。Awkは、他のほとんどの標準的なUnixツールと同様に、行バッファリングを実行します。(さらに、{print $0}印刷は条件が満たされたときのデフォルトのアクションであるため、は冗長です。)
tripleee
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.