Оптимизация GNU grep

8

Я использую egrep ( grep -E) с файлом PATTERN. ( -f path/to/file).

Это делается в бесконечном цикле в потоке текста. Это означает, что я не могу накапливать и передавать ВСЕ входные данные в grep одновременно (как *.log).

Есть ли способ заставить grep "сохранить" NFA, которую он создает из файла PATTERN, чтобы использовать его для следующего запуска?

Я искал Google и прочитал документацию без удачи.

Я постараюсь объяснить это немного больше. Мне нужно найти фиксированное количество строк с помощью регулярных выражений (это не является частью вопроса, но вы можете предложить иное), таких как IP-адреса, домены и т. Д. Поиск осуществляется по каналу из Интернета. Вы можете думать об этом как о текстовом потоке. Я не могу использовать grepвсе входные данные, так как это поток. Я могу накопить кусок потока и использовать grepего (таким образом, не используяgrep в каждой строке), но это также ограничено (скажем, в течение 30 секунд).

Я знаю grep, строит NFA из всех его шаблонов (в моем случае из файла). Итак, мой вопрос здесь: могу ли я grepсохранить этот NFA для следующего запуска, поскольку он не изменится? Это сэкономило бы мне время на создание этого NFA каждый раз.

bergerg
источник
Что вы подразумеваете под этим в бесконечном цикле потока текста ? Вы говорите, что вы используете один grepна строку текста? Откуда приходит текст? Был tail -fбы вариант?
Стефан
Допустим, я накапливаю поток в течение 30 секунд, а затем запускаю grepэтот фрагмент.
Бергерг
1
До сих пор не ясно, зачем вам нужно запускаться grepнесколько раз. Возможно, связано: Почему сопоставление 1250 строк с образцами 90 КБ происходит так медленно?
Стефан
5
grepпредназначен для работы с потоком текста, я до сих пор не понимаю, зачем вам нужно запускать несколько экземпляров. Почему вы не можете накормить всех этих в одном grepэкземпляре? Зачем вам их накапливать перед кормлением grep?
Стефан
2
Посмотрите на flex и напишите свою собственную программу, которая может оказаться намного быстрее.
user2064000

Ответы:

14

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

Хотя посмотрите, почему сопоставление 1250 строк с образцами 90 КБ так медленно? об ошибке в некоторых версиях GNUgrep , которая делает его особенно медленным для большого количества регулярных выражений.

Возможно, здесь вы могли бы избежать запуска grepнесколько раз, подавая свои куски в один и тот же grepэкземпляр, например, используя его как совместный процесс и используя маркер для определения конца. С zshи GNU grepи awkреализации, кроме mawk:

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped

Хотя может быть проще сделать все это с awkили perlвместо.

Но если вам не нужно grepвыводить данные в разные файлы для разных кусков, вы всегда можете сделать:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output
Стефан Шазелас
источник
У меня есть veraion 3+ из grep, так что это не проблема. Даже не подумал о разветвлении над головой. Я думаю, что я постараюсь транслировать все grepкак есть. Спасибо.
Бергерг
Разве исполняемый файл и разделяемые библиотеки не останутся в буферах ОЗУ после завершения процессов (если на самом деле OP не имеет мало ОЗУ)?
Дмитрий Григорьев
2
@DmitryGrigoryev, да, скорее всего, все еще нужно отобразить в адресном пространстве процесса и сделать редактирование ссылки. Это больше похоже на загрузку и разбор данных локали, анализ опций, среды ... Дело в том, что стоимость regcomp () уменьшается во всех этих накладных расходах. Первое, что нужно сделать при оптимизации, - это избегать запуска нескольких greps.
Стефан
1

Я не могу использовать grep на всех входах, так как это поток. Я могу накопить кусок потока и использовать grep на нем ...

Вы знаете, что блокируют трубопроводы? Если вы передадите что-то в grep и все входные данные будут недоступны, grep будет ждать, пока это не станет доступным, а затем продолжит, как если бы вход был там все время.

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

РЕДАКТИРОВАТЬ: Как конвейеры работают, например, с тем cmd1 | cmd2, что обе программы будут запускаться одновременно, например, между ними 65356-байтовый «буфер чанка». Когда cmd2попытка чтения и этот буфер пуст, он будет ждать, пока блок не будет доступен. Когда cmd1попытка записи и этот буфер заполнен, он будет ждать, пока cmd2его не прочитает.

Из того, что я могу прочитать, нет необходимости разрезать входные данные на куски и передавать их в grep отдельно. Это уже сделано автоматически.

EDIT2: grepтакже должен распечатать результаты, как только он найдет их в потоке. Нет необходимости завершать поток, прежде чем вы сможете получить свои результаты.

Йол
источник
0

Может быть, вы можете «использовать grep на всех входах»? Используя nc(netcat), или через script, или через другие, подобные инструменты? Особенно, если ваш файл шаблонов имеет управляемый размер (скажем, менее 1000 регулярных выражений).

Первый пример : Вы можете egrepподключиться к потоковому соединению: (здесь показан пример nc, но могут применяться и другие)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(примечание: вы можете даже: touch /some/path/results.gzперед запуском ncкоманды и иметь tail -fв этом (пустом) файле ничего не пропустить. В любом случае results.gz будет содержать все, что вы хотели поймать)

Второй пример : Вы могли бы даже egrepв текущем сеансе оболочки (и показать другой способ следовать прогрессии):

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egrepявляется высокоэффективной версией для grepбольшинства систем (см. интересную информацию по адресу : https://swtch.com/~rsc/regexp/regexp1.html ).

Оливье Дюлак
источник
Вы можете даже использовать instancele1 для таких вещей, как вывод dd и т. д.
Оливье Дюлак
Интересное примечание: grep тем эффективнее, чем больше известная часть регулярного выражения (например: поиск строки или регулярного выражения sнамного медленнее, чем сопоставление, somethingи это намного медленнее сопоставления something even much longer(последний позволяет совпадению регулярного выражения пропускать больше части входных данных при различиях.) В больших файлах он в основном «делит» время, чтобы проанализировать его на соотношение длины (т. е. поиск одного известного символа почти в 40 раз медленнее, чем сопоставление строки из 40 известных символов. но это действительно заметно.)
Оливье Дюлак