Respostas:
o grep's -oproduzirá apenas as correspondências, ignorando as linhas; wcpode 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
\be \Bfaz aqui?
uniqremove apenas as linhas idênticas adjacentes, sortantes de alimentar, uniqse 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 sedand 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 ^needleou \bneedleem needleneedle).
sed 's/needle/\n&\n/g' | grep -cx 'needle'
Observe que nas substituições sed acima, eu costumava \nsignificar 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 needlecomo separador de campo:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Se você deseja corresponder needleseguido 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>.