web-dev-qa-db-ja.com

逆グレッピング

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

44
user78433

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
46
chaos

このソリューションは役立つかもしれません:

tac file_name | grep -e expression
17
Anveshak

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

 tac hugeproduction.log | grep -m1 WhatImLookingFor

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

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

必要でない限り、-i(大文字と小文字は区別されません)を使用しないでください。使用すると、grepの速度が低下します。

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

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

ファイルが本当に大きく、メモリに収まらない場合は、PerlFile :: 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
9
cuonglm