2012-05-19 25 views
6

Ho un file, list.txt che contiene un elenco di parole. Voglio controllare quante volte ogni parola appare in un altro file, file1.txt, quindi restituire i risultati. Un semplice output di tutti i numeri è sufficiente, in quanto posso aggiungerli manualmente a list.txt con un programma di foglio di calcolo, ma se lo script aggiunge i numeri alla fine di ogni riga in list.txt, è ancora meglio, ad esempio:Conta quante volte ogni parola di un elenco di parole appare in un file?

bear 3 
fish 15 

ho provato questo, ma non funziona:

cat list.txt | grep -c file1.txt 
+1

Hai dimenticato di menzionare il formato del file di input. Una parola per riga? Le "parole" possono contenere spazi vuoti? Che dire del set di dati in cui grep? – 0xC0000022L

+0

'list.txt1' è una parola per riga. Una parola può avere alcuni spazi. I dati in 'file1.txt' sono molte frasi, ma una linea non si rompe mai su più linee. – Village

risposta

8

è possibile farlo in un ciclo che legge una sola parola alla volta da un file di word-list, e poi conta le istanze in un file di dati. Per esempio:

while read; do 
    echo -n "$REPLY " 
    fgrep -ow "$REPLY" data.txt | wc -l 
done < <(sort -u word_list.txt) 

La "salsa segreta" è composto da:

  1. usando la variabile REPLY implicita;
  2. utilizzando la sostituzione di processo per raccogliere parole dal file elenco di parole; e
  3. assicurando che si sta grepping per parole intere nel file di dati.
+3

Questo conterà il numero di linee corrispondenti, non il numero di occorrenze effettive (se ci sono più corrispondenze su una linea, sarà conteggiato come una sola). In teoria, 'fgrep -o -c' dovrebbe risolvere questo problema, ma non ha funzionato correttamente in alcune versioni recenti di GNU' coreutils'. – tripleee

+1

Grande cattura, @ triplo. Quello era un caso limite che non avevo considerato. Ho aggiornato la risposta per risolvere il tuo caso d'uso. –

3

Questo potrebbe funzionare per voi (GNU SED):

tr -s ' ' '\n' file1.txt | 
sort | 
uniq -c | 
sed -e '1i\s|.*|& 0|' -e 's/\s*\(\S*\)\s\(\S*\)\s*/s|\\<\2\\>.*|\2 \1|/' | 
sed -f - list.txt 

Spiegazione:

  • Split file1.txt in parole
  • Ordina le parole
  • Contare le parole
  • Creare uno script sed su mat ch le parole (inizialmente azzerare ogni parola)
  • eseguire lo script precedente contro la list.txt
4

Questo metodo awk solo deve passare attraverso ogni file una volta:

awk ' 
    # read the words in list.txt 
    NR == FNR {count[$1]=0; next} 
    # process file1.txt 
    { 
    for (i=0; i<=NF; i++) 
     if ($i in count) 
     count[$i]++ 
    } 
    # output the results 
    END { 
    for (word in count) 
     print word, count[word] 
    } 
' list.txt file1.txt 
+0

+1 per nessun ordinamento, un singolo passaggio attraverso l'input, nessun file temporaneo. Se si desidera conservare l'ordine da 'list.txt' nell'output, è facile aggiungere un indice in un secondo array al caso' NR == FNR'. – tripleee

1

comando singola linea

L'ultima parte del comando dice a grep di leggere le parole che corrispondono alla lista (opzione -f) e quindi corrisponde a parole intere (-w) cioè se list.txt c contiene auto, grep dovrebbe ignorare il trasporto.

Tuttavia, tieni presente che la visualizzazione della parola intera e della visualizzazione di grep potrebbe essere diversa. per es. anche se la macchina non combacia con il trasporto, si accoppierà con l'autolavaggio, noterai che "-" sarà considerato per il confine delle parole. grep accetta qualsiasi cosa eccetto lettere, numeri e underscore come limite della parola. Quale non dovrebbe essere un problema siccome questo è conforme alla definizione accettata di una parola in lingua inglese.

Problemi correlati