Считать общее количество вхождений с помощью grep

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

Я ищу что-то более элегантное, чем:

perl -e '$_ = <>; print scalar ( () = m/needle/g ), "\n"'
152 голоса | спросил user4518 6 FebruaryEurope/MoscowbSun, 06 Feb 2011 18:21:04 +0300000000pmSun, 06 Feb 2011 18:21:04 +030011 2011, 18:21:04

6 ответов


218

grep's -o выводит только совпадения, игнорируя строки; wc может подсчитать их:

grep -o 'needle' file | wc -l

Это также будет соответствовать «иглам» или «многоуровневому».
Только отдельные слова:

grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
ответил wag 6 FebruaryEurope/MoscowbSun, 06 Feb 2011 19:27:46 +0300000000pmSun, 06 Feb 2011 19:27:46 +030011 2011, 19:27:46
13

Если у вас есть GNU grep (всегда на Linux и Cygwin, иногда в другом месте), вы можете подсчитать выходные строки из grep -o : grep -o needle | wc -l.

С Perl, вот несколько способов, которые я нахожу более элегантными, чем ваши (даже после того, как он фиксированной ).

perl -lne 'END {print $c} map ++$c, /needle/g'
perl -lne 'END {print $c} $c += s/needle//g'
perl -lne 'END {print $c} ++$c while /needle/g'

При использовании только инструментов POSIX один подход, если это возможно, состоит в том, чтобы разделить входные данные на строки с одним совпадением, прежде чем передавать его в grep. Например, если вы ищете целые слова, сначала переверните каждый символ без слова в новую строку.

# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'

В противном случае стандартная команда не будет выполнять этот конкретный бит обработки текста, поэтому вам нужно обратиться к sed (если вы мазохист) или awk.

awk '{while (match($0, /set/)) {++c; $0=substr($0, RSTART+RLENGTH)}}
     END {print c}'
sed -n -e 's/set/\n&\n/g' -e 's/^/\n/' -e 's/$/\n/' \
       -e 's/\n[^\n]*\n/\n/g' -e 's/^\n//' -e 's/\n$//' \
       -e '/./p' | wc -l

Вот более простое решение, использующее sed и grep, который работает для строк или даже по отдельности, но не работает в нескольких угловых случаях с привязанными шаблонами ( например, он находит два вхождения ^needle или \bneedle в needleneedle).

sed 's/needle/\n&\n/g' | grep -cx 'needle'

Обратите внимание, что в приведенных выше методах sed я использовал \n для обозначения новой строки. Это стандартно в части шаблона, но в заменяющем тексте, для переносимости, замените обратную косую черту-новую строку для \n.

ответил Gilles 15 Maypm11 2011, 16:36:05
2

Другое решение, использующее awk и needle в качестве разделителя полей:

awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'

Если вы хотите совместить needle, за которым следует пунктуация, измените разделитель полей соответственно i.e.

awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'

Или используйте класс: [^[:alnum:]], чтобы охватить все неабсолютные символы.

ответил ripat 15 Maypm11 2011, 17:54:45
2

Если, как и я, вы действительно хотели "оба: каждый раз один раз", (это на самом деле "или два раза"), то это просто:

grep -E "thing1|thing2" -c

и проверьте вывод 2.

Преимущество этого подхода (если ровно один раз , что вы хотите) заключается в том, что он легко масштабируется.

ответил OJFord 13 Jpm1000000pmFri, 13 Jan 2017 16:20:11 +030017 2017, 16:20:11
1

В вашем примере выводится только количество вхождений в строке, а не общее количество в файле. Если это то, что вы хотите, что-то вроде этого может работать:

perl -nle '$c+=scalar(()=m/needle/g);END{print $c}' 
ответил jsbillings 6 FebruaryEurope/MoscowbSun, 06 Feb 2011 18:41:36 +0300000000pmSun, 06 Feb 2011 18:41:36 +030011 2011, 18:41:36
1

Это мое чистое решение bash

#!/bin/bash

B=$(for i in $(cat /tmp/a | sort -u); do
echo "$(grep $i /tmp/a | wc -l) $i"
done)

echo "$B" | sort --reverse
ответил Felipe 9 AM00000010000003731 2012, 01:31:37

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132