web-dev-qa-db-fra.com

Grevre inversée

Disons que j'ai un très gros fichier texte (environ 10 000 000 lignes). J'ai besoin de grep it It à partir de la fin et de sauvegarder un résultat à un fichier. Quel est le moyen le plus efficace d'accomplir une tâche?

44
user78433

TAC /grep solution

tac file | grep whatever

Ou un peu plus efficace:

grep whatever < <(tac file)

Temps avec un fichier de 500 Mo:

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

SED/GREP solution:

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

Temps avec un fichier de 500 Mo: avorté après plus de 10 minutes.

awk/grep solution:

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

Temps avec un fichier de 500 Mo:

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

Perl/Grep Solution:

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

Temps avec un fichier de 500 Mo:

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

Cette solution pourrait aider:

tac file_name | grep -e expression
17
Anveshak

Celui-ci sort dès qu'il trouve le premier match:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Ce qui suit donne les 5 lignes avant et après les deux premiers matchs:

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

N'oubliez pas de ne pas utiliser -i (cas insensible) sauf si vous ne devez que cela ralentira le grep.

Si vous connaissez la chaîne exacte que vous recherchez, considérez alors fgrep (chaîne fixe)

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

Si le fichier est vraiment gros, je ne peux pas utiliser la mémoire, je vais utiliser Perl avec fichier :: readbackwards module de 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;

Puis:

$ ./reverse-grep.pl pattern file
9
cuonglm