Membalikkan grepping

44

Katakanlah, saya memiliki file teks yang sangat besar (sekitar 10.000.000 baris). Saya perlu grepdari awal dan menyimpan hasilnya ke file. Apa cara paling efisien untuk menyelesaikan tugas?

kekacauan
sumber
10
Gunakan tacdan grepuntuk mencapai apa yang Anda inginkan.
Valentin Bajrami
1
Selain solusi luar biasa yang diposting, GNU juga grepmemiliki --max-count (number)saklar yang batal setelah sejumlah pertandingan, yang mungkin menarik bagi Anda.
Ulrich Schwarz
@ val0x00ff dapatkah Anda melihat pertanyaan ini
c0rp
Apakah Anda tahu berapa banyak hit yang akan Anda miliki? Ketika Anda berpikir grep Anda akan menemukan 3 garis, mulailah grepping dan mundur sesudahnya.
Walter A

Jawaban:

46

Solusi tac / grep

tac file | grep whatever

Atau sedikit lebih efektif:

grep whatever < <(tac file)

Waktu dengan file 500MB:

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

Solusi sed / grep :

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

Waktu dengan file 500MB: Dibatalkan setelah 10+ menit.

Solusi awk / grep :

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

Waktu dengan file 500MB:

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

Solusi perl / grep :

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

Waktu dengan file 500MB:

real    0m3.551s
user    0m3.104s
sys     0m1.036s
kekacauan
sumber
2
sed, awkdan perl(dengan metode ini) tidak OK karena mereka membaca file dari awal, yang sangat tidak efisien. Saya kira itu tacmelakukan hal yang benar.
vinc17
1
@ vinc17 ya, statistik waktu menunjukkan apa yang Anda katakan.
kekacauan
2
@ val0x00ff < <(tac filename)Harus secepat pipa: dalam kedua kasus, perintah dijalankan secara paralel.
vinc17
7
Jika Anda ingin efisiensi, akan lebih baik untuk menempatkan tacsetelah grep. Jika Anda memiliki 10.000.000 file baris, dengan hanya 2 yang cocok, Anda tachanya perlu membalikkan 2 baris, bukan 10m. grepmasih akan harus melalui semuanya.
Patrick
3
Jika Anda meletakkan tacsetelah grep, itu akan membaca dari pipa dan tidak bisa mencari. Itu akan membuatnya kurang efisien (atau gagal sepenuhnya) jika jumlah garis yang ditemukan besar.
jjanes
17

Solusi ini mungkin membantu:

tac file_name | grep -e expression
Anveshak
sumber
3
tacadalah perintah GNU. Pada kebanyakan sistem lain, padanannya adalah tail -r.
Stéphane Chazelas
@ Stéphane: Pada setidaknya beberapa sistem Unix, tail -rterbatas pada sejumlah kecil garis, ini mungkin menjadi masalah.
RedGrittyBrick
1
@RedGrittyBrick, apakah Anda memiliki referensi untuk itu, atau bisakah Anda memberi tahu sistem mana yang memiliki batasan itu?
Stéphane Chazelas
@ StéphaneChazelas, tail -r /etc/passwdgagal dengan tail: invalid option -- 'r'. Saya menggunakan coreutils-8.21-21.fc20.x86_64.
Cristian Ciupitu
@CristianCiupitu, seperti yang saya katakan, GNU memiliki tac(dan hanya GNU yang memiliki tac) yang dimiliki banyak Unix lainnya tail -r. GNU tailtidak mendukung-r
Stéphane Chazelas
10

Yang ini keluar segera setelah menemukan kecocokan pertama:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Berikut ini memberikan 5 baris sebelum dan setelah dua pertandingan pertama:

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

Ingatlah untuk tidak menggunakan -i(case sensitive) kecuali Anda harus karena itu akan memperlambat grep.

Jika Anda tahu string yang tepat yang Anda cari, pertimbangkan fgrep(Fixed String)

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

Jika file tersebut sangat besar, tidak dapat disimpan dalam memori, saya akan menggunakan Perldengan File :: ReadBackwards modul dari 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;

Kemudian:

$ ./reverse-grep.pl pattern file
cuonglm
sumber
Keuntungan dari pendekatan ini adalah Anda dapat mengubah Perl untuk melakukan apa pun yang Anda inginkan.
zzapper
1
@zzapper: Ini juga hemat memori, karena ketika membaca file baris demi baris, bukannya menyeruput file dalam memori seperti tac.
cuonglm
adakah yang bisa menambahkan dukungan -m untuk ini? Saya ingin menguji file nyata. Lihat: gist.githubusercontent.com/ychaouche/…
ychaouche