Подсчитайте количество вхождений паттерна в файл (даже на одной строке)
при поиске количества вхождений строки в файл, я обычно использую:
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
.нет.
этот ярлык не будет работать во всех случаях. 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