Ответы:
grep's -oбудет выводить только совпадения, игнорируя строки; wcможно их посчитать
grep -o 'needle' file | wc -l
Это также будет соответствовать «иглам» или «многоигольным иглам».
Только отдельные слова:
grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
\bи \Bделать здесь?
uniqудаляет только смежные идентичные строки, которые вам нужно sortперед подачей, uniqесли вы еще не уверены, что дубликаты всегда будут соседними.
Если у вас есть 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.
Если, как и я, вы на самом деле хотели «оба; каждый ровно один раз» (это на самом деле «либо; дважды»), тогда все просто:
grep -E "thing1|thing2" -c
и проверьте вывод 2.
Преимущество этого подхода (если только один раз это то , что вы хотите), что она легко масштабируется.
Другое решение с использованием awk и в needleкачестве разделителя полей:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Если вы хотите, чтобы совпадение needleсопровождалось пунктуацией, измените разделитель полей соответственно, т.е.
awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'
Или используйте класс: [^[:alnum:]]для охвата всех не буквенных символов.
В вашем примере выводится только количество вхождений на строку, а не общее количество в файле. Если это то, что вы хотите, что-то вроде этого может работать:
perl -nle '$c+=scalar(()=m/needle/g);END{print $c}'
grepэто указано, но для всехack, кто использует , ответ простоack -ch <pattern>.