Подсчитать количество вхождений шаблона в файле (даже в одной строке)

При поиске количества вхождений строки в файле я обычно использую:

grep pattern file | wc -l

Однако, это находит только одно вхождение на строку, из-за того, как работает grep. Как я могу искать, сколько раз строка появляется в файле, независимо от того, находятся ли они в одной или разных строках?

Кроме того, что, если я ищу шаблон регулярного выражения, а не простую строку? Как я могу их посчитать или, что еще лучше, напечатать каждое совпадение на новой строке?

5 ответов

Решение

Для подсчета всех случаев используйте -o, Попробуй это:

echo afoobarfoobar | grep -o foo | wc -l

А также man grep конечно (:

Обновить

Некоторые предлагают использовать просто grep -co foo вместо grep -o foo | wc -l,

Не.

Этот ярлык не будет работать во всех случаях. Страница человека говорит:

-c print a count of matching lines

Разница в этих подходах иллюстрируется ниже:

1.

$ echo afoobarfoobar | grep -oc foo
1

Как только совпадение будет найдено в строке (a{foo}barfoobar) поиск прекращается. Только одна строка была проверена и соответствует, поэтому вывод 1, На самом деле -o здесь игнорируется, и вы можете просто использовать grep -c вместо.

2.

$ echo afoobarfoobar | grep -o foo
foo
foo

$ echo afoobarfoobar | grep -o foo | wc -l
2

Два совпадения найдены в строке (a{foo}bar{foo}bar) потому что мы явно просили найти каждое вхождение (-o). Каждый случай печатается на отдельной строке, и wc -l просто считает количество строк в выводе.

Попробуй это:

grep "string to search for" FileNameToSearch | cut -d ":" -f 4 | sort -n | uniq -c

Образец:

grep "SMTP connect from unknown" maillog | cut -d ":" -f 4 | sort -n | uniq -c
  6  SMTP connect from unknown [188.190.118.90]
 54  SMTP connect from unknown [62.193.131.114]
  3  SMTP connect from unknown [91.222.51.253]

Ripgrep, которая является быстрой альтернативой grep, только что представила --count-matches флаг, позволяющий подсчитывать каждое совпадение в версии 0.9 (я использую приведенный выше пример для обеспечения согласованности):

> echo afoobarfoobar | rg --count foo
1
> echo afoobarfoobar | rg --count-matches foo
2

По просьбе OP, ripgrep также позволяет использовать регулярные выражения (--regexp <PATTERN>). Также он может печатать каждое (строковое) совпадение на отдельной строке:

> echo -e "line1foo\nline2afoobarfoobar" | rg foo
line1foo
line2afoobarfoobar

Запоздалый пост:
Используйте шаблон регулярного выражения поиска как разделитель записей (RS) в awk
Это позволяет вашему регулярному выражению охватывать \n-ограниченные линии (если вам это нужно).

printf 'X \n moo X\n XX\n' | 
   awk -vRS='X[^X]*X' 'END{print (NR<2?0:NR-1)}'

Взломайте цветовую функцию grep и посчитайте, сколько цветных меток она распечатывает:

echo -e "a\nb  b b\nc\ndef\nb e brb\nr" \
| GREP_COLOR="033" grep --color=always  b \
| perl -e 'undef $/; $_=<>; s/\n//g; s/\x1b\x5b\x30\x33\x33/\n/g; print $_' \
| wc -l
Другие вопросы по тегам