Підрахувати кількість повторень шаблону у файлі (навіть на одному рядку)


94

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

grep pattern file | wc -l

Однак це знаходить лише одне входження в рядок, через те, як працює grep. Як я можу шукати, скільки разів рядок з’являється у файлі, незалежно від того, знаходяться вони в одному рядку чи в різних рядках?

Крім того, що робити, якщо я шукаю шаблон регулярного виразу, а не простий рядок? Як я можу порахувати їх, або, що ще краще, надрукувати кожен збіг у новому рядку?

Відповіді:


157

Для підрахунку всіх випадків використовуйте -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просто підраховується кількість рядків у вихідних даних.


1
Ого ... це справді так просто?
jrdioko

1
grep -oc у цьому випадку не працює. Спробуйте echo afoobarfoobar | grep -oc foo
Паулюс

Чи немає можливості зробити це для кількох файлів? Скажімо, я хочу бачити кількість випадків, що виникають в одному файлі для набору файлів. Я можу робити це на рядок з grep -c *, але не на екземпляр.
Кіт Тайлер

grep -o foo a.txt b.txt | sort | uniq -cчудово працює (з GNU grep): gist.github.com/hudolejev/81a05791f38cbacfd4de3ee3b44eb4f8
hudolejev

2

Спробуйте це:

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]

1

Запізнілий допис:
Використовуйте шаблон awk
регулярного \nвиразу як роздільник записів (RS) у розділі Це дозволяє вашому регулярному виразу розширювати рядки, розділені (якщо вам це потрібно).

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

0

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

-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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.