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?
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
Cette solution pourrait aider:
tac file_name | grep -e expression
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'
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