逆grepping


44

たとえば、非常に大きなテキストファイル(約10.000.000行)があるとします。grep最後からそれをする必要があり、結果をファイルに保存します。タスクを達成する最も効率的な方法は何ですか?


10
tacおよびgrepを使用して、目的を達成します。
バレンティンバジラミ14

1
投稿された優れたソリューションに加えて、GNUにgrep--max-count (number)、一定回数一致した後に中断するスイッチがあります。これは興味深いかもしれません。
ウルリッヒ・シュワルツ14

@ val0x00ffあなたが見てとることができ、この質問
c0rp

どれだけヒットするか知っていますか?grepで3行が見つかると思われる場合は、grepを開始し、その後元に戻します。
ウォルターA

回答:


46

tac / grepソリューション

tac file | grep whatever

またはもう少し効果的:

grep whatever < <(tac file)

500MBファイルの時間:

real    0m1.225s
user    0m1.164s
sys     0m0.516s

sed / grepソリューション:

sed '1!G;h;$!d' | grep whatever

500MBファイルの場合:10分以上経過すると中断されます。

awk / grepソリューション:

awk '{x[NR]=$0}END{while (NR) print x[NR--]}' file | grep whatever

500MBファイルの時間:

real    0m5.626s
user    0m4.964s
sys     0m1.420s

perl / grepソリューション:

perl -e 'print reverse <>' file | grep whatever

500MBファイルの時間:

real    0m3.551s
user    0m3.104s
sys     0m1.036s

2
sedawkおよびperl(このメソッドでは)ファイルを最初から読み取るため、OKではありません。これは非常に非効率的です。それtacは正しいことだと思います。
vinc17 14

1
@ vinc17はい、時間統計はあなたが言ったことを指します。
カオス14

2
@ val0x00ff < <(tac filename)はパイプと同じ速さである必要があります。どちらの場合も、コマンドは並行して実行されます。
vinc17 14

7
効率を上げる場合はtac、grep の後に置く方が良いでしょう。マッチtacが2つしかない10,000,000行のファイルがある場合は、10mではなく2行だけ逆にする必要があります。grepいずれにせよ、まだすべてを実行する必要があります。
パトリック

3
tac後に置くgrepと、パイプから読み取られるため、シークできません。見つかった行の数が多い場合、効率が低下します(または完全に失敗します)。
jjanes 14

17

この解決策が役立つ場合があります。

tac file_name | grep -e expression

3
tacGNUコマンドです。他のほとんどのシステムでは、同等のものはtail -rです。
ステファンシャゼル

@Stéphane:少なくとも一部のUnixシステムでtail -rは、行数が少ないため、これが問題になる可能性があります。
RedGrittyBrick 14

1
@RedGrittyBrick、そのための参考資料はありますか、またはどのシステムにその制限があるのか​​教えていただけますか?
ステファンシャゼル14

@StéphaneChazelasは、でtail -r /etc/passwd失敗しtail: invalid option -- 'r'ます。coreutils-8.21-21.fc20.x86_64を使用しています。
クリスティアン・Ciupitu

@CristianCiupitu、私が言ったように、GNUにはtac(そしてGNUにのみtacが)他の多くのUnicesがありtail -rます。GNUはtailサポートしていません-r
ステファンChazelas

10

これは、最初の一致が見つかるとすぐに終了します。

 tac hugeproduction.log | grep -m1 WhatImLookingFor

以下は、最初の2つの一致の前後の5行を示しています。

 tac hugeproduction.log | grep -m2 -A 5 -B 5 WhatImLookingFor

-igrepを遅くする必要がある場合を除き、(大文字と小文字を区別しない)使用しないでください。

探している正確な文字列がわかっている場合は、fgrep(固定文字列)を検討してください

 tac hugeproduction.log | grep -F -m2 -A 5 -B 5 'ABC1234XYZ'

9

ファイルが本当に大きく、メモリに収まらない場合Perl、次のFile :: ReadBackwardsモジュールで使用しますCPAN

$ cat reverse-grep.pl
#!/usr/bin/perl

use strict;
use warnings;

use File::ReadBackwards;

my $pattern = shift;
my $rev = File::ReadBackwards->new(shift)
    or die "$!";

while (defined($_ = $rev->readline)) {
    print if /$pattern/;
}

$rev->close;

次に:

$ ./reverse-grep.pl pattern file

このアプローチの利点は、Perlを微調整して任意の操作を行えることです。
ザッパー14

1
@zzapper:メモリ内のファイルを丸ごと読み込むのではなく、1行ずつファイルを読み取るため、メモリ効率も高くなりますtac
cuonglm

誰でもこれに-mサポートを追加できますか?実際のファイルでテストしたいと思います。参照:gist.githubusercontent.com/ychaouche/...
ychaouche
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.