grep -c es útil para encontrar cuántas veces ocurre una cadena en un archivo , pero solo cuenta cada aparición una vez por línea. ¿Cómo contar múltiples ocurrencias por línea?

Estoy buscando algo más elegante que:

perl -e "$_ = <>; print scalar ( () = m/needle/g ), "\n"" 

Comentarios

  • Sé que se especifica grep, pero para cualquiera que use ack, la respuesta es simplemente ack -ch <pattern>.
  • @KyleStrand Para mí ack -ch < patrón > solo contó las líneas con ocurrencias y no el número de ocurrencias
  • @MarcKees Mirando la página del manual, suena como el comportamiento correcto. ¡Gracias por señalarlo!

Answer

grep «s -o solo generará las coincidencias, ignorando las líneas; wc puede contarlos:

grep -o "needle" file | wc -l 

Esto también coincidirá con «agujas» o «multiagujas».

Para hacer coincidir solo palabras individuales, use uno de los siguientes comandos:

grep -ow "needle" file | wc -l grep -o "\bneedle\b" file | wc -l grep -o "\<needle\>" file | wc -l 

Comentarios

  • Tenga en cuenta que esto requiere GNU grep (Linux, Cygwin, FreeBSD, OSX).
  • @wag ¿Qué magia hace \b y \B ¿aquí?
  • @Geek \ b coincide con un límite de palabra, \ B NO coincide con un límite de palabra. La respuesta anterior sería más correcta si usara \ b en ambos extremos.
  • Para un recuento de ocurrencias por línea, combine con la opción grep -n y uniq -c … grep -no ' \ < aguja \ > ' archivo | uniq -c
  • @jameswarren uniq solo elimina las líneas idénticas adyacentes, debe sort antes de alimentar a uniq si aún no está seguro de que los duplicados siempre serán inmediatamente adyacentes.

Responder

Si tiene GNU grep (siempre en Linux y Cygwin, ocasionalmente en otros lugares), puede contar las líneas de salida de grep -o : grep -o needle | wc -l.

Con Perl, aquí hay algunas formas que encuentro más elegantes que las suyas (incluso después de que «s fijo ).

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 el ingrese en líneas con una sola coincidencia antes de pasarlo 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 hacer esto s un poco particular de procesamiento de texto, por lo que debe recurrir a 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í» una solución más simple usando 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 ( p.ej 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, utilicé \n para significar una nueva línea. Esto es estándar en la parte del patrón, pero en el texto de reemplazo, por portabilidad, sustituya la barra invertida-nueva línea por \n.

Respuesta

Si, como yo, en realidad querías «ambos; cada uno exactamente una vez», (esto es en realidad «cualquiera; dos veces») entonces es simple :

grep -E "thing1|thing2" -c 

y verifique el resultado 2.

El beneficio de este enfoque (si exactamente una vez es lo que desea) es que se escale fácilmente.

Comentarios

  • I ' No estoy seguro de que ' estés comprobando que ' solo aparece una vez. ¿Todos los ' Lo que busca es que alguna de esas palabras exista al menos una vez.
  • Esta debería ser la respuesta aceptada. No es necesario utilizar wc -l, grep tiene una opción incorporada para contar cosas, e incluso se denomina como obvia como -c para «count»!

Answer

Otro solución usando awk y needle como separador de campo:

awk -F"^needle | needle | needle$" "{c+=NF-1}END{print c}" 

Si desea hacer 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 alfabéticos.

Comentarios

  • Tenga en cuenta que esto requiere un awk que admita separadores de campos regexp (como GNU awk).

Respuesta

Esta es mi solución bash pura

#!/bin/bash B=$(for i in $(cat /tmp/a | sort -u); do echo "$(grep $i /tmp/a | wc -l) $i" done) echo "$B" | sort --reverse 

Respuesta

Su ejemplo solo imprime el número de ocurrencias por línea, y no el total en el archivo. Si eso es lo que desea, algo como esto podría funcionar:

perl -nle "$c+=scalar(()=m/needle/g);END{print $c}" 

Comentarios

  • Usted tienen razón, mi ejemplo solo cuenta las ocurrencias en la primera línea.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *