Odwrotne grepowanie


44

Powiedzmy, że mam naprawdę duży plik tekstowy (około 10.000.000 linii). Muszę to grepzrobić od końca i zapisać wynik w pliku. Jaki jest najbardziej efektywny sposób wykonania zadania?


10
Użyj taci, grepaby osiągnąć to, czego chcesz.
Valentin Bajrami

1
Oprócz opublikowanych doskonałych rozwiązań, GNU grepma --max-count (number)przełącznik, który przerywa określoną liczbę dopasowań, co może być dla ciebie interesujące.
Ulrich Schwarz,

@ val0x00ff czy możesz spojrzeć na to pytanie
c0rp

Czy wiesz, ile trafień będziesz miał? Kiedy myślisz, że twój grep znajdzie 3 linie, zacznij grep i odwróć później.
Walter A

Odpowiedzi:


46

Rozwiązanie tac / grep

tac file | grep whatever

Lub nieco bardziej efektywny:

grep whatever < <(tac file)

Czas z plikiem 500 MB:

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

Rozwiązanie sed / grep :

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

Czas z plikiem 500 MB: Przerwany po ponad 10 minutach.

awk / grep Rozwiązanie:

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

Czas z plikiem 500 MB:

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

Rozwiązanie perl / grep :

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

Czas z plikiem 500 MB:

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

2
sed, awkI perl(w tej metodzie) nie są w porządku, ponieważ odczytać plik od początku, co jest bardzo nieefektywne. Przypuszczam, że tacrobi to dobrze.
vinc17

1
@ vinc17 tak, statystyki czasu wskazują na to, co powiedziałeś.
chaos

2
@ val0x00ff < <(tac filename)Powinien być tak szybki jak potok: w obu przypadkach polecenia są uruchamiane równolegle.
vinc17

7
Jeśli szukasz wydajności, lepiej ustawić tacgrep. Jeśli masz plik 10 000 000 linii, zawierający tylko 2 dopasowania, tacbędziesz musiał odwrócić tylko 2 linie, a nie 10 m. grepnadal będzie musiał przejść przez to wszystko w jedną stronę.
Patrick

3
Jeśli wstawisz tacpo grep, będzie czytać z fajki, więc nie możesz szukać. To sprawi, że będzie mniej wydajna (lub całkowicie zawiedzie), jeśli liczba znalezionych linii jest duża.
jjanes

17

To rozwiązanie może pomóc:

tac file_name | grep -e expression

3
tacto polecenie GNU. W większości innych systemów odpowiednikiem jest tail -r.
Stéphane Chazelas

@ Stéphane: Przynajmniej w niektórych systemach uniksowych tail -rjest ograniczony do niewielkiej liczby linii, może to być problem.
RedGrittyBrick

1
@RedGrittyBrick, czy masz jakieś odniesienia do tego, czy możesz powiedzieć, które systemy mają to ograniczenie?
Stéphane Chazelas

@ StéphaneChazelas, tail -r /etc/passwdkończy się niepowodzeniem tail: invalid option -- 'r'. Używam coreutils-8.21-21.fc20.x86_64.
Cristian Ciupitu,

@CristianCiupitu, jak już powiedziałem, GNU ma tac(i tylko GNU ma tac) wiele innych Uników tail -r. GNU tailnie obsługuje-r
Stéphane Chazelas,

10

Ten kończy działanie, gdy tylko znajdzie pierwsze dopasowanie:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Poniżej podano 5 linii przed i po pierwszych dwóch meczach:

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

Pamiętaj, aby nie używać -i(bez rozróżniania wielkości liter), chyba że musisz, ponieważ spowolni to grep.

Jeśli znasz dokładny ciąg, którego szukasz, rozważ fgrep(Naprawiono ciąg)

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

9

Jeśli plik jest naprawdę duży, nie mieści się w pamięci, skorzystam Perlz modułu File :: ReadBackwards z 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;

Następnie:

$ ./reverse-grep.pl pattern file

Zaletą tego podejścia jest to, że możesz dostosować Perla do robienia wszystkiego, co chcesz.
zzapper

1
@zzapper: Jest również wydajny pod względem pamięci, ponieważ odczytuje plik linia po linii zamiast pliku slurp w pamięci jak tac.
cuonglm

czy ktoś może dodać do tego obsługę -m? Chciałbym przetestować prawdziwe pliki. Zobacz: gist.githubusercontent.com/ychaouche/…
ychaouche
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.