Ответы:
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>
.