Respuestas:
grep -o
solo dará salida a las coincidencias, ignorando las líneas; wc
puede contarlos:
grep -o 'needle' file | wc -l
Esto también coincidirá con 'agujas' o 'multineedle'.
Solo palabras sueltas:
grep -o '\bneedle\B' file | wc -l
# or:
grep -o '\<needle\>' file | wc -l
\b
y \B
hace aquí?
uniq
solo elimina las líneas idénticas adyacentes, es necesario hacerlo sort
antes de alimentar uniq
si no está seguro de que los duplicados siempre serán inmediatamente adyacentes.
Si tiene grep de GNU (siempre en Linux y Cygwin, de vez en cuando en otros lugares), puede contar las líneas de salida degrep -o
: grep -o needle | wc -l
.
Con Perl, aquí hay algunas formas en que me parece más elegante que la tuya (incluso después de que se solucione ).
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'
Con solo herramientas POSIX, un enfoque, si es posible, es dividir la entrada en líneas con una sola coincidencia antes de pasarla a grep. Por ejemplo, si está buscando palabras completas, primero convierta cada carácter que no sea una palabra en una nueva línea.
# equivalent to grep -ow 'needle' | wc -l
tr -c '[:alnum:]' '[\n*]' | grep -c '^needle$'
De lo contrario, no hay un comando estándar para realizar este procesamiento de texto en particular, por lo que debe activar sed (si es un masoquista) o 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
Aquí hay una solución más simple que usa sed
y grep
, que funciona para cadenas o incluso expresiones regulares según el libro, pero falla en algunos casos de esquina con patrones anclados (por ejemplo, encuentra dos ocurrencias de ^needle
o \bneedle
en needleneedle
).
sed 's/needle/\n&\n/g' | grep -cx 'needle'
Tenga en cuenta que en las sustituciones sed anteriores, solía \n
significar una nueva línea. Esto es estándar en la parte del patrón, pero en el texto de reemplazo, para portabilidad, sustituya la barra diagonal inversa-nueva línea \n
.
Si, como yo, realmente quería "ambos; cada uno exactamente una vez", (esto es en realidad "cualquiera; dos veces"), entonces es simple:
grep -E "thing1|thing2" -c
y verifique la salida 2
.
El beneficio de este enfoque (si exactamente una vez es lo que desea) es que se escala fácilmente.
Otra solución usando awk y needle
como separador de campo:
awk -F'^needle | needle | needle$' '{c+=NF-1}END{print c}'
Si desea coincidir needle
seguido de puntuación, cambie el separador de campo en consecuencia, es decir
awk -F'^needle[ ,.?]|[ ,.?]needle[ ,.?]|[ ,.?]needle$' '{c+=NF-1}END{print c}'
O use la clase: [^[:alnum:]]
para abarcar todos los caracteres no alfa.
Su ejemplo solo imprime el número de ocurrencias por línea, y no el total en el archivo. Si eso es lo que quieres, algo como esto podría funcionar:
perl -nle '$c+=scalar(()=m/needle/g);END{print $c}'
grep
está especificado, pero para cualquiera que lo useack
, la respuesta es sencillaack -ch <pattern>
.