¿Cómo cuento el número de apariciones de una palabra en un archivo de texto con la línea de comando?

43

Tengo un archivo JSON grande que está en una línea, y quiero usar la línea de comando para poder contar el número de apariciones de una palabra en el archivo. ¿Cómo puedo hacer eso?

mythz
fuente
No está claro si la palabra debe coincidir tanto en las claves como en los valores de los datos JSON, es decir, si { "key": "the key" }debe contar la cadena keyuna o dos veces.
Kusalananda

Respuestas:

46
$ tr ' ' '\n' < FILE | grep WORD | wc -l

Donde trreemplaza espacios con líneas nuevas, grepfiltra todas las líneas resultantes que coinciden con WORD y wccuenta las restantes.

Incluso se puede guardar la wcparte utilizando la -copción de grep:

$ tr ' ' '\n' < FILE | grep -c WORD

La -copción está definida por POSIX.

Si no se garantiza que haya espacios entre las palabras, debe usar algún otro carácter (como delimitador) para reemplazar. Por ejemplo, las trpartes alternativas son

tr '"' '\n'

o

tr "'" '\n'

si desea reemplazar comillas dobles o simples. Por supuesto, también puede usar trpara reemplazar varios caracteres a la vez (piense en diferentes tipos de espacios en blanco y puntuación).

En caso de que necesite contar WORD pero no prefixWORD, WORDsuffix o prefixWORDsuffix, puede encerrar el patrón WORD en los marcadores de inicio / fin de línea:

grep -c '^WORD$'

Lo que es equivalente a los marcadores de inicio / fin de palabra, en nuestro contexto:

grep -c '\<WORD\>'
maxschlepzig
fuente
¿Qué pasa si no hay espacios, es decir, el nombre del campo está rodeado de comillas? por ejemplo, "campo"
mythz
@ mythz: Luego reemplaza las comillas con líneas nuevas con tr. Actualizaré la respuesta.
maxschlepzig
1
Esta respuesta es incorrecta en muchos sentidos. Es vago: debe explicar cómo crear un trcomando que haga el trabajo en lugar de sugerir ejemplos que nunca funcionarán en todas las situaciones. También coincidirá con palabras que contengan la palabra que está buscando. La grep -o '\<WORD\>' | wc -lsolución es muy superior.
sam hocevar
1
@Sam, la pregunta lo deja un poco abierto, si una palabra buscada debe buscarse como 'PALABRA' o '\ <PALABRA \>', puede leerla en ambos sentidos. Incluso si lo lees de la segunda manera y solo de la segunda, mi respuesta sería incorrecta de una sola manera. ;) Y la solución 'grep -o' solo es superior, si admite la opción -o, que no está especificada por POSIX ... Bueno, no creo que el uso de tr sea tan exótico como para llamarlo vago ...
maxschlepzig
1
@Kusalananda, bueno, todavía es un hecho. Pero si no desea contar esas coincidencias de subcadenas, lea el último párrafo de mi respuesta y mi comentario anterior aquí.
maxschlepzig
24

Con GNU grep, esto funciona: grep -o '\<WORD\>' | wc -l

-o imprime cada parte coincidente de cada línea en una línea separada.

\<afirma el comienzo de una palabra y \>afirma el final de una palabra (similar a la de Perl \b), por lo que esto garantiza que no coincida una cadena en el medio de una palabra.

Por ejemplo,

$ python -c 'importa esto' | grep '\ <one \>'
Debe haber una , y preferiblemente solo una, forma obvia de hacerlo.
Los espacios de nombres son una gran idea, ¡hagamos más de eso!
$ python -c 'importa esto' | grep -o '\ <one \>'
 one 
one 
one 
$ python -c 'import this' | grep -o '\ <one \>' | wc -l
3
efímero
fuente
1
O simplementegrep -wo WORD | wc -l
Stéphane Chazelas
10

Esto desafortunadamente no funciona con GNU coreutils.

grep -o -c WORD file

Si funciona en su plataforma, es una solución elegante y bastante intuitiva; pero la gente de GNU todavía está pensando.

tripleee
fuente
2
Lo malo es que el error aún está abierto: savannah.gnu.org/bugs/?33080
tripleee el
1
Lástima que esto hubiera sido lo más elegante
MasterScrat
¡Esto funcionó para mí!
ThisaruG
Esto está mal. Esto cuenta el número de líneas con el patrón WORD. El OP quiere el número total de ocurrencias.
Pierre B
@PierreB Por eso digo que GNU greptiene un error aquí. Desde POSIX no está claro cuál es la semántica de combinar -cy -odebería ser, por lo que actualmente no es portátil. Gracias por el comentario; He actualizado esta respuesta.
tripleee
7
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

Este comando hace lo siguiente:

  1. Sustituya todos los caracteres no alfanuméricos con un espacio en blanco.
  2. Todos los saltos de línea también se convierten en espacios.
  3. Reduce todos los espacios en blanco múltiples a un espacio en blanco
  4. Todos los espacios ahora se convierten en saltos de línea. Cada palabra en una línea.
  5. Traduce todas las palabras a minúsculas para evitar que 'Hola' y 'hola' sean palabras diferentes
  6. Clases de texto
  7. Cuenta y elimina las líneas iguales
  8. Ordena en reversa para contar las palabras más frecuentes
  9. Agregue un número de línea a cada palabra para conocer la posición de la palabra en su totalidad.

Por ejemplo, si quiero analizar el primer mensaje de Linus Torvald:

De: [email protected] (Linus Benedict Torvalds) Grupos de noticias: comp.os.minix Asunto: ¿Qué le gustaría ver más en minix? Resumen: pequeña encuesta para mi nuevo sistema operativo ID de mensaje: <[email protected]> Fecha: 25 de agosto 91 20:57:08 GMT Organización: Universidad de Helsinki

Hola a todos por ahí usando minix -

Estoy haciendo un sistema operativo (gratuito) (solo un hobby, no será grande y profesional como gnu) para 386 (486) clones AT. Esto se ha estado gestando desde abril y está comenzando a prepararse. Me gustaría recibir comentarios sobre cosas que a la gente le gustan / disgustan en minix, ya que mi sistema operativo se parece un poco (el mismo diseño físico del sistema de archivos (debido a razones prácticas), entre otras cosas).

Actualmente he portado bash (1.08) y gcc (1.40), y las cosas parecen funcionar. Esto implica que obtendré algo práctico dentro de unos meses, y me gustaría saber qué características desearía la mayoría de las personas. Cualquier sugerencia es bienvenida, pero no prometo implementarla 🙂

Linus ([email protected])

PD. Sí, está libre de cualquier código minix y tiene un fs multiproceso. NO es protable (utiliza el cambio de tareas 386, etc.), y probablemente nunca admitirá nada más que discos duros AT, ya que eso es todo lo que tengo :-(.

Creo un archivo llamado linus.txt , pego el contenido y luego escribo en la consola:

sed -e 's/[^[:alpha:]]/ /g' linus.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl 

La salida sería:

 1        7 i
 2        5 to
 3        5 like
 4        5 it
 5        5 and
 6        4 minix
 7        4 a
 8        3 torvalds
 9        3 of
10        3 helsinki
11        3 fi
12        3 any
13        2 would
14        2 won
15        2 what
16        ...

Si desea visualizar solo las primeras 20 palabras:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | head -n 20

Es importante tener en cuenta que el comando tr 'AZ' 'a-z' no se suport UTF-8 sin embargo , de modo que en las lenguas extranjeras la palabra APRÈS se traducirían como après.

Si solo desea buscar la aparición de una palabra, puede agregar un grep al final:

sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\sword_to_search_for$"

En un script llamado search_freq :

#!/bin/bash
sed -e 's/[^[:alpha:]]/ /g' text_to_analize.txt | tr '\n' " " |  tr -s " " | tr " " '\n'| tr 'A-Z' 'a-z' | sort | uniq -c | sort -nr | nl | grep "\s$1$"

El script debe llamarse:

 search_freq word_to_search_for
Roger Borrell
fuente
sed: -e expression #2, char 7: unterminated s 'comando', también esto cuenta todas las palabras, ¿verdad? Pero OP solo preguntó una en particular. También un poco de explicación sería bueno.
phk
Lo siento, tuve un error. He rehecho el comando más comentado la respuesta. En mi opinión, de la pregunta, es imposible saber si le gustaría obtener la aparición de una sola palabra o una frecuencia de ocurrencias. Pero en caso de que desee obtener solo una palabra, puede agregar un grep al final.
Roger Borrell
3

Dependiendo de si desea hacer coincidir la palabra en las claves o en los valores de los datos JSON, es probable que desee extraer solo claves o solo valores de los datos. De lo contrario, puede contar algunas palabras demasiadas veces si aparecen como claves y valores.

Para extraer todas las claves:

jq -r '..|objects|keys[]' <file.json

Esto prueba de forma recursiva si lo actual es un objeto y, si lo es, extrae las claves. La salida será una lista de claves, una por línea.

Para extraer todos los valores:

jq -r '..|scalars' <file.json

Esto funciona de manera similar, pero tiene menos pasos.

Luego puede canalizar la salida de lo anterior a través de grep -c 'PATTERN'(para hacer coincidir algún patrón con las claves o valores), o grep -c -w -F 'WORD'(para hacer coincidir una palabra en las claves o valores), o grep -c -x -F 'WORD'(para hacer coincidir una clave o valor completo), o similar, para Haz tu recuento.

Kusalananda
fuente
0

Tengo json con algo como esto: "number":"OK","number":OK"repetido varias veces en una línea.

Mi simple contador "OK":

sed "s|,|\n|g" response | grep -c OK

khazad-dum_miner
fuente
-1

He usado el siguiente comando awk para encontrar el número de ocurrencias

archivo de ejemplo

gato archivo1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

mando:

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

salida

awk '{print gsub("praveen",$0)}' file1 | awk 'BEGIN{sum=0}{sum=sum+$1}END{print sum}'

5
Praveen Kumar BS
fuente
O simplemente awk '{sum+=gsub("praveen","")} END {print sum+0}'.
G-Man dice 'Reincorporar a Monica' el
Hágame saber por qué abajo votar por mi respuesta
Praveen Kumar BS