Greppen rückwärts

44

Nehmen wir an, ich habe eine sehr große Textdatei (ca. 10.000.000 Zeilen). Ich muss grepes vom Ende an und als Ergebnis in eine Datei speichern. Was ist der effizienteste Weg, um eine Aufgabe zu erledigen?

Chaos
quelle
10
Verwenden Sie tacund grep, um das zu erreichen, was Sie wollen.
Valentin Bajrami
1
Zusätzlich zu den ausgezeichneten Lösungen, die veröffentlicht wurden, grepverfügt GNU über einen --max-count (number)Schalter, der nach einer bestimmten Anzahl von Übereinstimmungen abgebrochen wird, was für Sie interessant sein könnte.
Ulrich Schwarz
@ Val0x00ff könnten Sie einen Blick auf diese Frage
werfen
Wissen Sie, wie viele Treffer Sie haben werden? Wenn Sie glauben, dass Ihr Grep 3 Zeilen findet, beginnen Sie mit dem Greifen und kehren Sie anschließend um.
Walter A

Antworten:

46

tac / grep Lösung

tac file | grep whatever

Oder etwas effektiver:

grep whatever < <(tac file)

Zeit mit einer 500MB Datei:

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

sed / grep Lösung:

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

Zeit mit einer 500MB-Datei: Abgebrochen nach mehr als 10 Minuten.

awk / grep Lösung:

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

Zeit mit einer 500MB Datei:

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

perl / grep Lösung:

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

Zeit mit einer 500MB Datei:

real    0m3.551s
user    0m3.104s
sys     0m1.036s
Chaos
quelle
2
sed, awkund perl(mit dieser Methode) sind nicht OK, da sie die Datei von Anfang an lesen, was sehr ineffizient ist. Ich nehme an, tacdas ist das Richtige.
Vinc17
1
@vinc17 ja, die zeitstatistik zeigt was du gesagt hast.
Chaos
2
@ val0x00ff Die < <(tac filename)sollte so schnell wie eine Pipe sein: In beiden Fällen werden die Befehle parallel ausgeführt.
Vinc17
7
Wenn Sie Effizienz anstreben, ist es besser, das tacnach dem Grep zu setzen. Wenn Sie eine 10.000.000-Zeilen-Datei mit nur 2 Übereinstimmungen haben, tacmüssen Sie nur 2 Zeilen umkehren, nicht 10 m. grepwird immer noch die ganze Sache so oder so durchmachen müssen.
Patrick
3
Wenn Sie tacnach dem setzen grep, wird es aus einer Pipe gelesen und kann so nicht suchen. Das macht es weniger effizient (oder scheitert komplett), wenn die Anzahl der gefundenen Zeilen groß ist.
Jjanes
17

Diese Lösung könnte helfen:

tac file_name | grep -e expression
Anveshak
quelle
3
tacist der GNU-Befehl. Auf den meisten anderen Systemen ist das Äquivalent tail -r.
Stéphane Chazelas
@Stéphane: Auf zumindest einigen Unix-Systemen, tail -rdie auf eine geringe Anzahl von Zeilen beschränkt sind, könnte dies ein Problem sein.
RedGrittyBrick
1
@ RedGrittyBrick, haben Sie eine Referenz dafür, oder können Sie bitte sagen, welche Systeme diese Einschränkung haben?
Stéphane Chazelas
@ StéphaneChazelas, tail -r /etc/passwdscheitert mit tail: invalid option -- 'r'. Ich verwende coreutils-8.21-21.fc20.x86_64.
Cristian Ciupitu
@CristianCiupitu, wie gesagt, GNU hat tac(und nur GNU hat tac) viele andere Unices tail -r. GNU tailunterstützt nicht-r
Stéphane Chazelas
10

Dieser wird beendet, sobald er die erste Übereinstimmung findet:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Das Folgende gibt die 5 Zeilen vor und nach den ersten beiden Übereinstimmungen an:

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

Denken Sie daran, nicht -i(Groß- / Kleinschreibung wird nicht berücksichtigt) zu verwenden, es sei denn, Sie müssen dies tun, um das Grep zu verlangsamen.

Wenn Sie die genaue Zeichenfolge kennen, die Sie suchen, ziehen Sie in Betracht fgrep(feste Zeichenfolge )

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

Wenn die Datei wirklich groß ist, nicht in den Speicher passen kann, werde ich Perlmit File :: ReadBackwards Modul aus 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;

Dann:

$ ./reverse-grep.pl pattern file
cuonglm
quelle
Der Vorteil dieses Ansatzes ist, dass Sie das Perl optimieren können, um alles zu tun, was Sie wollen.
zzapper
1
@zzapper: Es ist auch speichereffizient, da es Datei Zeile für Zeile liest, anstatt Datei im Speicher zu schlürfen tac.
Cuonglm
Kann jemand eine -m-Unterstützung dafür hinzufügen? Ich würde gerne echte Dateien testen. Siehe: gist.githubusercontent.com/ychaouche/…
ychaouche