Эффективный поиск нескольких строк в текстовом файле

Я использую egrep для поиска точных совпадений нескольких строк в очень длинном файле (1 миллион строк):

egrep "\<string1\>|<\string2\>" my_file

Но даже на то, чтобы найти всего две строки, уходит слишком много времени. Кажется, что он ищет каждую строку по всем строкам файла, даже если находит вхождение. Действительно, я знаю, что файл содержит только одно вхождение каждой строки. Затем я хотел бы знать, как заставить egrep прекратить поиск строки, как только он найдет ее вхождение, и искать следующую в списке. Или если есть другой способ сделать это эффективно.

Спасибо.


person saloua    schedule 05.10.2012    source источник
comment
Сколько строк вы хотите найти? Горстка или что-то вроде нескольких тысяч?   -  person Jo So    schedule 05.10.2012


Ответы (3)


Есть опция -m, которая ограничивает количество совпадений:

-m NUM, --max-count=NUM
     Stop reading a file after NUM matching lines.

Однако вы не можете использовать его напрямую со своим сложным шаблоном, потому что тогда вы получите только 1 строку для всех подшаблонов. Что вы можете сделать, так это перебрать ваши подшаблоны, вызывая fgrep -m 1:

for pat in $patterns; do
    fgrep -m 1 $pat my_file
done

P.S. Другой вариант — использовать сложный шаблон, как вы, и указать количество совпадений, равное количеству подшаблонов, но это приведет к более медленному сравнению для каждой строки файла.

person Lev Levitsky    schedule 05.10.2012
comment
Спасибо за Ваш ответ. Я получил это с помощью --max-count=NUM - person saloua; 05.10.2012
comment
В сторону: учитывая, что OP знает, что каждая строка встречается не более одного раза в файле, среднее ускорение от --max-count=1 составляет всего 200%. - person Jo So; 05.10.2012
comment
Я думаю, что сложный шаблон с совпадениями, равными количеству подшаблонов, на самом деле будет самым быстрым; см. мой ответ для объяснения. - person Gordon Davisson; 06.10.2012

То, как вы должны оптимизировать поиск, зависит от того, какой алгоритм использует ваша реализация grep. «Традиционный» алгоритм для egrep заключается в компиляции шаблона в детерминированный конечный автомат. Если вы не знаете, что это такое, не беспокойтесь: важно то, что компиляция занимает некоторое время, но как только это сделано, она выполняется довольно быстро, и ее скорость не зависит от сложности просматриваемого шаблона. за. На самом деле, после компиляции egrep работает быстрее, чем fgrep — это означает, что fgrep быстрее работает с маленькими файлами, а egrep — с большими файлами.

По крайней мере, так обстоит дело с традиционными реализациями [ef]grep. Я думаю, что большинство современных реализаций являются адаптивными и будут переключать алгоритмы в зависимости от ситуации (например, я думаю, что современные fgreps будут переключаться в скомпилированный режим DFA для достаточно больших файлов). Чтобы выяснить, что является самым быстрым для вашей реализации, вам действительно нужно попробовать несколько экспериментов по времени.

Тем не менее, я могу дать вам несколько рекомендаций: во-первых, избегайте запускать поиск более одного раза (например, запускать fgrep для каждого слова), потому что это будет означать многократное сканирование файла. Во-вторых, не беспокойтесь о том, чтобы свести к минимуму количество строк, которые он ищет, потому что, если вы находитесь в наилучшем возможном режиме, это все равно не будет иметь значения. В-третьих, используйте предложение @Lev о -m, чтобы остановить его после того, как он найдет то, что ему нужно (хотя я почти уверен, что это будет одиночный поиск обоих слов с -m2).

person Gordon Davisson    schedule 06.10.2012
comment
Очень хороший ответ, спасибо. Наконец заставил меня пойти и посмотреть DFA :) - person Lev Levitsky; 06.10.2012

Я не уверен, но, возможно, этот быстрее:

grep -e '<pattern1>' -e '<pattern2>' -e '<pattern3>' your_file

-F также может ускорить процесс, я думаю, что ваши шаблоны на самом деле не являются шаблонами. Кроме того, я думаю, что если ваш вывод окрашен, у grep нет другого выбора, кроме как искать все шаблоны.

person Michael Krelin - hacker    schedule 05.10.2012
comment
Я заменил шаблон слова строкой, так лучше :) Я должен использовать egrep, потому что я избегаю зацикливания, выбрасывающего массив, содержащий искомые строки. Затем я просто использую расширение параметра, чтобы получить то, что я написал. И, наконец, используйте egrep, чтобы найти их. - person saloua; 05.10.2012
comment
Я до сих пор не понимаю, зачем вам egrep. Чем он лучше grep -F -e 'string1' -e 'string2' -e 'string3' your_file. Вы пробовали, кстати? - person Michael Krelin - hacker; 05.10.2012
comment
И да, как предполагает Лев, добавление -m 2 в эту командную строку тоже должно улучшить ситуацию, я сначала не понял, что у вас есть только одна совпадающая строка для каждого шаблона, а не только один шаблон в строке. - person Michael Krelin - hacker; 05.10.2012