Обратная очистка

44

Допустим, у меня действительно большой текстовый файл (около 10.000.000 строк). Мне нужно grepэто с конца и сохранить результат в файл. Какой самый эффективный способ выполнить задачу?

хаос
источник
10
Используйте tacи grepдобиться того, что вы хотите.
Валентин Байрами
1
Помимо опубликованных отличных решений, в GNU grepесть --max-count (number)переключатель, который прерывает работу после определенного числа совпадений, которые могут вас заинтересовать.
Ульрих Шварц
@ val0x00ff не могли бы вы взглянуть на этот вопрос
c0rp
Вы знаете, сколько хитов у вас будет? Когда вы думаете, что ваш grep найдет 3 строки, начните grep и затем поверните вспять.
Уолтер А

Ответы:

46

TAC / grep Solution

tac file | grep whatever

Или немного эффективнее:

grep whatever < <(tac file)

Время с файлом 500 МБ:

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

Решение sed / grep :

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

Время с файлом 500 МБ: прервано через 10+ минут.

Решение awk / grep :

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

Время с файлом 500 МБ:

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

Perl / grep Решение:

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

Время с файлом 500 МБ:

real    0m3.551s
user    0m3.104s
sys     0m1.036s
хаос
источник
2
sed, awkИ perl(с помощью этого метода) не в порядке , так как они читают файл с самого начала, что очень неэффективно. Я полагаю, что tacэто правильно.
vinc17
1
@ vinc17 да, статистика времени указывает на то, что вы сказали.
хаос
2
@ val0x00ff < <(tac filename)Должен быть таким же быстрым, как конвейер: в обоих случаях команды выполняются параллельно.
vinc17
7
Если вы собираетесь на эффективность, было бы лучше поставить tacпосле grep. Если у вас есть файл с 10 000 000 строк и только 2 совпадения, вам tacнужно будет перевернуть только 2 строки, а не 10 м. grepвсе равно придется пройти через все это в любом случае.
Патрик
3
Если вы поставите tacпосле grep, он будет читать из трубы и поэтому не может искать. Это сделает его менее эффективным (или полностью потерпит неудачу), если количество найденных строк велико.
Джанес
17

Это решение может помочь:

tac file_name | grep -e expression
Anveshak
источник
3
tacэто команда GNU. В большинстве других систем, то эквивалент tail -r.
Стефан Шазелас
@ Стефан: По крайней мере, на некоторых системах Unix tail -rограничено небольшим количеством строк, это может быть проблемой.
RedGrittyBrick
1
@RedGrittyBrick, есть ли у вас какие-либо ссылки на это, или не могли бы вы сказать, какие системы имеют это ограничение?
Стефан Шазелас
@ StéphaneChazelas, tail -r /etc/passwdне удается с tail: invalid option -- 'r'. Я использую coreutils-8.21-21.fc20.x86_64.
Кристиан Чиупиту
@CristianCiupitu, как я уже сказал, у GNU есть tac(и только у GNU есть tac) многие другие Unices tail -r. GNU tailне поддерживает-r
Стефан Шазелас
10

Этот выходит, как только находит первое совпадение:

 tac hugeproduction.log | grep -m1 WhatImLookingFor

Ниже приведены 5 строк до и после первых двух совпадений:

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

Помните, что не следует использовать -i(без учета регистра), за исключением случаев, когда это замедляет работу grep.

Если вы знаете точную строку, которую вы ищете, подумайте fgrep(Фиксированная строка)

 tac hugeproduction.log | grep -F -m2 -A 5 -B 5 'ABC1234XYZ'
zzapper
источник
9

Если файл действительно большой, не может поместиться в памяти, я буду использовать Perlс File :: ReadBackwards модуль из 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;

Затем:

$ ./reverse-grep.pl pattern file
cuonglm
источник
Преимущество этого подхода заключается в том, что вы можете настроить Perl, чтобы делать все что угодно.
zzapper
1
@zzapper: Это также эффективно использует память, так как когда он читает файл построчно, а не файл slurp в памяти, как tac.
cuonglm
Кто-нибудь может добавить поддержку -m для этого? Я хотел бы проверить реальные файлы. См. Gist.githubusercontent.com/ychaouche/…
ychaouche