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


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

grep pattern file | wc -l

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

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

5 82

5 ответов:

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

echo afoobarfoobar | grep -o foo | wc -l

и man grep конечно (:

обновление

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

нет.

этот ярлык не будет работать во всех случаях. Man page говорит:

-c print a count of matching lines

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

1.

$ echo afoobarfoobar | grep -oc foo
1

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

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]

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

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

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

взломать цветовую функцию 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