Come contare il numero di occorrenze di una parola in un file di testo con la riga di comando?


43

Ho un file JSON di grandi dimensioni che si trova su una riga e desidero utilizzare la riga di comando per poter contare il numero di occorrenze di una parola nel file. Come lo posso fare?


Non è chiaro se la parola debba essere abbinata sia nelle chiavi che nei valori dei dati JSON, ovvero se si { "key": "the key" }debba contare la stringa keyuna o due volte.
Kusalananda

Risposte:


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

Dove trsostituisce gli spazi con le nuove linee, grepfiltra tutte le linee risultanti corrispondenti a WORD e wcconta quelle rimanenti.

Si può anche salvare la wcparte usando l' -copzione grep:

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

L' -copzione è definita da POSIX.

Se non è garantito che ci siano spazi tra le parole, è necessario utilizzare qualche altro carattere (come delimitatore) per sostituire. Ad esempio trparti alternative sono

tr '"' '\n'

o

tr "'" '\n'

se vuoi sostituire le virgolette doppie o singole. Naturalmente, puoi anche utilizzare trper sostituire più caratteri contemporaneamente (pensa a diversi tipi di spazi bianchi e punteggiatura).

Nel caso in cui sia necessario contare WORD ma non prefixWORD, WORDsuffix o prefixWORDsuffix, è possibile racchiudere il modello WORD nei marcatori di inizio / fine riga:

grep -c '^WORD$'

Che è equivalente ai marcatori di inizio / fine della parola, nel nostro contesto:

grep -c '\<WORD\>'

cosa succede se non ci sono spazi, ovvero il nome del campo è racchiuso tra virgolette? es. "field"
mythz,

@mythz: Quindi sostituisci le virgolette con le nuove righe con tr. Aggiornerò la risposta.
maxschlepzig,

1
Questa risposta è errata in molti modi. È vago: dovresti spiegare come elaborare un trcomando che fa il lavoro invece di suggerire esempi che non funzioneranno mai in tutte le situazioni. Abbinerà anche le parole che contengono la parola che stai cercando. La grep -o '\<WORD\>' | wc -lsoluzione è di gran lunga superiore.
sam hocevar,

1
@Sam, la domanda lo lascia in qualche modo aperto, se una parola cercata deve essere cercata come 'WORD' o '\ <WORD \>' - puoi leggerla in entrambi i modi. Anche se lo leggi nel 2 ° modo e solo nel 2 ° modo, la mia risposta sarebbe errata solo in 1 modo. ;) E la soluzione 'grep -o' è solo superiore, se supporta l'opzione -o - che non è specificata da POSIX ... Beh, non penso che l'uso di tr sia così esotico da chiamarlo vago ...
maxschlepzig

1
@Kusalananda, beh, è ​​ancora un evento. Ma se non vuoi contare tali corrispondenze di sottostringhe, leggi l'ultimo paragrafo della mia risposta e il mio commento precedente qui.
maxschlepzig

24

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

-o stampa ciascuna parte corrispondente di ogni riga su una riga separata.

\<afferma l'inizio di una parola e \>afferma la fine di una parola (simile a quella di Perl \b), quindi questo assicura che non abbini una stringa nel mezzo di una parola.

Per esempio,

$ python -c 'importa questo' | grep '\ <one \>'
Dovrebbe esserci un modo - e preferibilmente solo uno - di essere accessibile per farlo.
Gli spazi dei nomi sono una grande idea che suona il clacson: facciamo di più!
$ python -c 'importa questo' | grep -o '\ <one \>'
 one 
one 
one 
$ python -c 'import this' | grep -o '\ <one \>' | wc -l
3

1
O semplicementegrep -wo WORD | wc -l
Stéphane Chazelas,

10

Questo purtroppo non funziona con GNU coreutils.

grep -o -c WORD file

Se funziona sulla tua piattaforma, è una soluzione elegante e abbastanza intuitiva; ma la gente GNU sta ancora pensando.


2
Mio male, il bug è ancora aperto: savannah.gnu.org/bugs/?33080
tripleee

1
Peccato che questo sarebbe stato il più elegante
MasterScrat

Questo ha funzionato per me!
ThisaruG,

Questo è sbagliato. Questo conta il numero di righe con il modello WORD. L'OP vuole il numero totale di occorrenze.
Pierre B,

@PierreB Ecco perché sto dicendo che GNU grepha un bug qui. Da POSIX non è chiaro quale sia la semantica della combinazione -ce -odovrebbe essere quindi questo non è attualmente portatile. Grazie per il commento; Ho aggiornato questa risposta.
triplo

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 

Questo comando effettua quanto segue:

  1. Sostituisci tutti i caratteri non alfanumerici con uno spazio vuoto.
  2. Anche tutte le interruzioni di riga vengono convertite in spazi.
  3. Riduce tutti gli spazi vuoti multipli in uno spazio vuoto
  4. Tutti gli spazi vengono ora convertiti in interruzioni di riga. Ogni parola in una riga.
  5. Traduce tutte le parole in minuscolo per evitare che "Hello" e "Hello" siano parole diverse
  6. Ordina testo
  7. Conta e rimuove le linee uguali
  8. Ordina al contrario per contare le parole più frequenti
  9. Aggiungi un numero di riga a ogni parola per conoscere la parola posotion nel suo insieme

Ad esempio, se voglio analizzare il primo messaggio di Linus Torvald:

Da: torvalds@klaava.Helsinki.FI (Linus Benedict Torvalds) Newsgroup: comp.os.minix Oggetto: Cosa ti piacerebbe vedere di più in minix? Riepilogo: piccolo sondaggio per il mio nuovo sistema operativo ID messaggio: <1991Aug25.205708.9541@klaava.Helsinki.FI> Data: 25 ago 91 20:57:08 GMT Organizzazione: Università di Helsinki

Ciao a tutti là fuori usando minix -

Sto facendo un sistema operativo (gratuito) (solo un hobby, non sarà grande e professionale come GNU) per 386 (486) cloni AT. Questo è stato preparato da aprile e sta iniziando a prepararsi. Vorrei un feedback su cose che piacciono / non piacciono alle persone in minix, dal momento che il mio sistema operativo lo assomiglia in qualche modo (stesso layout fisico del file system (per motivi pratici) tra le altre cose).

Al momento ho eseguito il porting di bash (1.08) e gcc (1.40), e le cose sembrano funzionare. Ciò implica che entro pochi mesi avrò qualcosa di pratico e mi piacerebbe sapere quali funzionalità la maggior parte delle persone vorrebbe. Eventuali suggerimenti sono ben accetti, ma non prometto che li implementerò 🙂

Linus (torvalds@kruuna.helsinki.fi)

PS. Sì, è privo di qualsiasi codice minix e ha un fs multi-thread. NON è protetto (utilizza 386 task switching ecc.) E probabilmente non supporterà mai nulla di diverso dai dischi rigidi AT, poiché è tutto ciò che ho :-(.

Creo un file chiamato linus.txt , incollo il contenuto e quindi scrivo nella console:

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

L'out messo sarebbe:

 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        ...

Se vuoi visualizzare solo le prime 20 parole:

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

È importante notare che il comando tr 'AZ' 'a-z' non si suport UTF-8 ma , in modo che in lingue straniere i APRÈS parola sarebbe tradotto come Après.

Se vuoi solo cercare la ricorrenza di una parola, puoi aggiungere un grep alla fine:

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$"

In uno script chiamato 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$"

Lo script deve essere chiamato:

 search_freq word_to_search_for

sed: -e expression #2, char 7: unterminated s 'comando`, anche questo conta tutte le parole, giusto? Ma OP ha chiesto solo uno in particolare. Anche un po 'di spiegazione sarebbe carino.
phk,

Scusa se ho sbagliato. Ho rifatto il comando e commentato la risposta. Secondo me, dalla domanda, è impossibile sapere se vorrebbe ottenere la valuta di una sola parola o una frequenza di occorrenze. Ma nel caso in cui desideri ottenere solo una parola, puoi aggiungere un grep alla fine.
Roger Borrell,

3

A seconda che si desideri abbinare la parola nelle chiavi o nei valori dei dati JSON, è probabile che si desideri estrarre solo le chiavi o solo i valori dai dati. Altrimenti potresti contare alcune parole troppe volte se si presentano sia come chiavi che come valori.

Per estrarre tutte le chiavi:

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

Questo verifica in modo ricorsivo se la cosa corrente è un oggetto e, se lo è, estrae le chiavi. L'output sarà un elenco di chiavi, una per riga.

Per estrarre tutti i valori:

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

Funziona in modo simile, ma ha meno passaggi.

È quindi possibile reindirizzare l'output di quanto sopra grep -c 'PATTERN'(per far corrispondere un modello a chiavi o valori), oppure grep -c -w -F 'WORD'(per abbinare una parola in chiavi o valori), o grep -c -x -F 'WORD'(per abbinare una chiave o un valore completo), o simili, a conta.


0

Ho json con qualcosa del genere: "number":"OK","number":OK"ripetuto più volte in una riga.

Il mio semplice contatore "OK":

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


-1

Ho usato sotto il comando awk per trovare il numero di occorrenze

file di esempio

file cat1

praveen ajay 
praveen
ajay monkey praveen
praveen boy praveen

comando:

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

produzione

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

5

O semplicemente awk '{sum+=gsub("praveen","")} END {print sum+0}'.
G-Man dice 'Reinstate Monica' il

Fammi sapere perché vota verso il basso per la mia risposta
Praveen Kumar BS
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.