Avversione inversa


44

Diciamo che ho un file di testo davvero grande (circa 10.000.000 di righe). Ne ho bisogno grepdalla fine e salvare il risultato in un file. Qual è il modo più efficiente per svolgere l'attività?


10
Usa tace grepper ottenere ciò che desideri.
Valentin Bajrami,

1
Oltre alle eccellenti soluzioni pubblicate, GNU grepha un --max-count (number)interruttore che si interrompe dopo un certo numero di partite, che potrebbe essere interessante per te.
Ulrich Schwarz,

@ val0x00ff potresti dare un'occhiata a questa domanda
c0rp

Sai quanti colpi avrai? Quando pensi che il tuo grep troverà 3 linee, inizia il grepping e invertilo dopo.
Walter,

Risposte:


46

Soluzione tac / grep

tac file | grep whatever

O un po 'più efficace:

grep whatever < <(tac file)

Tempo con un file da 500 MB:

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

soluzione sed / grep :

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

Tempo con un file da 500 MB: interrotto dopo 10+ minuti.

soluzione awk / grep :

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

Tempo con un file da 500 MB:

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

soluzione perl / grep :

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

Tempo con un file da 500 MB:

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

2
sed, awkE perl(con questo metodo) non sono a posto, visto che leggono il file dall'inizio, che è molto inefficiente. Suppongo che tacfaccia la cosa giusta.
vinc17,

1
@ vinc17 si, le statistiche temporali indicano ciò che hai detto.
caos,

2
@ val0x00ff < <(tac filename)Deve essere veloce come una pipe: in entrambi i casi, i comandi vengono eseguiti in parallelo.
vinc17,

7
Se stai cercando efficienza, sarebbe meglio mettere il tacdopo il grep. Se hai un file di 10.000.000 di righe, con solo 2 corrispondenze, tacdovrai solo invertire 2 righe, non 10m. grepdovrà ancora passare attraverso l'intera faccenda in entrambi i modi.
Patrick,

3
Se lo metti tacdopo grep, leggerà da una pipe e quindi non puoi cercare. Ciò renderà meno efficiente (o fallirà completamente) se il numero di linee trovate è elevato.
jjanes

17

Questa soluzione potrebbe aiutare:

tac file_name | grep -e expression

3
tacè il comando GNU. Sulla maggior parte degli altri sistemi, l'equivalente è tail -r.
Stéphane Chazelas,

@ Stéphane: su almeno alcuni sistemi Unix, tail -rè limitato a un piccolo numero di linee, questo potrebbe essere un problema.
RedGrittyBrick,

1
@RedGrittyBrick, hai qualche riferimento a riguardo o potresti dire per favore quali sistemi hanno questa limitazione?
Stéphane Chazelas,

@ StéphaneChazelas, tail -r /etc/passwdnon riesce tail: invalid option -- 'r'. Sto usando coreutils-8.21-21.fc20.x86_64.
Cristian Ciupitu,

@CristianCiupitu, come ho detto, GNU ha tac(e solo GNU ha tac) molti altri Unices tail -r. GNU tailnon supporta-r
Stéphane Chazelas il

10

Questo esce non appena trova la prima partita:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Quanto segue fornisce le 5 righe prima e dopo le prime due partite:

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

Ricorda di non usare -i(senza distinzione tra maiuscole e minuscole) a meno che tu non debba rallentare il grep.

Se conosci la stringa esatta che stai cercando, considera fgrep(String fissa)

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

9

Se il file è veramente grande, non può stare nella memoria, lo userò Perlcon il modulo File :: ReadBackwards da 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;

Poi:

$ ./reverse-grep.pl pattern file

Il vantaggio di questo approccio è che puoi modificare il Perl per fare tutto quello che vuoi.
zzapper,

1
@zzapper: è anche efficiente in termini di memoria, dal momento che quando leggeva file riga per riga anziché come file slurp in memoria come tac.
cuonglm,

qualcuno può aggiungere un supporto -m per questo? Mi piacerebbe testare su file reali. Vedi: gist.githubusercontent.com/ychaouche/…
ychaouche
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.