Respostas:
o grep's -o
produzirá apenas as correspondências, ignorando as linhas; wc
pode contá-los:
grep -o 'needle' file | wc -l
Isso também corresponderá a 'agulhas' ou 'multicamada'.
Apenas palavras simples:
grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
\b
e \B
faz aqui?
uniq
remove apenas as linhas idênticas adjacentes, sort
antes de alimentar, uniq
se ainda não tiver certeza de que as duplicatas sempre serão imediatamente adjacentes.
Se você tiver GNU grep (sempre em Linux e Cygwin, ocasionalmente, em outros lugares), você pode contar as linhas de saídagrep -o
: grep -o needle | wc -l
.
Com o Perl, aqui estão algumas maneiras que considero mais elegantes que as suas (mesmo depois de consertadas ).
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'
Com apenas ferramentas POSIX, uma abordagem, se possível, é dividir a entrada em linhas com uma única correspondência antes de passá-la para grep. Por exemplo, se você estiver procurando por palavras inteiras, primeiro transforme todos os caracteres que não sejam palavras em uma nova linha.
# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'
Caso contrário, não há um comando padrão para fazer esse processamento específico de texto, então você precisa recorrer ao sed (se você é masoquista) ou 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
Aqui está uma solução mais simples usando sed
and grep
, que funciona para strings ou mesmo expressões regulares, mas falha em alguns casos de canto com padrões ancorados (por exemplo, encontra duas ocorrências de ^needle
ou \bneedle
em needleneedle
).
sed 's/needle/\n&\n/g' | grep -cx 'needle'
Observe que nas substituições sed acima, eu costumava \n
significar uma nova linha. Isso é padrão na parte do padrão, mas no texto de substituição, para portabilidade, substitua a barra invertida-nova linha por \n
.
Se, como eu, você realmente queria "ambos; cada um exatamente uma vez" ((na verdade, é "qualquer um; duas vezes"), então é simples:
grep -E "thing1|thing2" -c
e verifique a saída 2
.
O benefício dessa abordagem (se exatamente uma vez é o que você deseja) é que ela pode ser dimensionada facilmente.
Outra solução usando awk e needle
como separador de campo:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Se você deseja corresponder needle
seguido de pontuação, altere o separador de campos de acordo.
awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'
Ou use a classe: [^[:alnum:]]
para abranger todos os caracteres não alfa.
Seu exemplo imprime apenas o número de ocorrências por linha, e não o total no arquivo. Se é isso que você deseja, algo como isso pode funcionar:
perl -nle '$c+=scalar(()=m/needle/g);END{print $c}'
grep
é especificado, mas para quem usaack
, a resposta é simplesack -ch <pattern>
.