Trova righe duplicate in un file e conta quante volte è stata duplicata ogni riga?


529

Supponiamo di avere un file simile al seguente:

123 
123 
234 
234 
123 
345

Vorrei scoprire quante volte '123' è stato duplicato, quante volte è stato duplicato '234', ecc. Quindi idealmente, l'output sarebbe come:

123  3 
234  2 
345  1

4
Che lingua vuoi usare?
VMAtm,

Risposte:


791

Supponendo che ci sia un numero per riga:

sort <file> | uniq -c

Puoi usare anche il --countflag più dettagliato con la versione GNU, ad esempio su Linux:

sort <file> | uniq --count

3
Questo è quello che faccio, comunque algoritmicamente, questo non sembra essere l'approccio più efficiente (O (n log n) * avg_line_len dove n è il numero di righe). Sto lavorando a file di diversi gigabyte, quindi le prestazioni sono un problema chiave. Mi chiedo se esiste uno strumento che esegue solo il conteggio in un singolo passaggio usando un albero dei prefissi (nel mio caso le stringhe hanno spesso prefissi comuni) o simili, che dovrebbe fare il trucco in O (n) * avg_line_len. Qualcuno conosce un tale strumento da riga di comando?
Droggl

21
Un ulteriore passaggio consiste nel convogliare l'output di quello in un comando finale 'sort -n'. Ciò ordinerà i risultati in base ai quali le linee si verificano più spesso.
samoz,

79
Se vuoi stampare solo righe duplicate, usa 'uniq -d'
DmitrySandalov

6
Se vuoi riordinare il risultato, puoi usarlo di sortnuovo come:sort <file> | uniq -c | sort -n
Abhishek Kashyap

414

Questo stamperà solo righe duplicate , con conteggi:

sort FILE | uniq -cd

oppure, con le opzioni GNU long (su Linux):

sort FILE | uniq --count --repeated

su BSD e OSX devi usare grep per filtrare le linee uniche:

sort FILE | uniq -c | grep -v '^ *1 '

Per l'esempio fornito, il risultato sarebbe:

  3 123
  2 234

Se si desidera stampare i conteggi per tutte le righe, comprese quelle visualizzate una sola volta:

sort FILE | uniq -c

oppure, con le opzioni GNU long (su Linux):

sort FILE | uniq --count

Per l'input specificato, l'output è:

  3 123
  2 234
  1 345

Per ordinare l'output con le righe più frequenti in alto, puoi fare quanto segue (per ottenere tutti i risultati):

sort FILE | uniq -c | sort -nr

oppure, per ottenere solo righe duplicate, prima le più frequenti:

sort FILE | uniq -cd | sort -nr

su OSX e BSD l'ultimo diventa:

sort FILE | uniq -c | grep -v '^ *1 ' | sort -nr

1
Buon punto con l'opzione --repeated o -d. Molto più preciso rispetto all'utilizzo di "| grep 2" o simile!
Lauri,

Come posso modificare questo comando per recuperare tutte le righe il cui numero di ripetizioni è superiore a 100?
Black_Rider,

@Black_Rider L'aggiunta | sort -no | sort -nralla pipe ordina l'output in base al conteggio delle ripetizioni (rispettivamente crescente o decrescente). Non è quello che stai chiedendo, ma ho pensato che potesse aiutare.
Andrea,

1
@Black_Rider awk sembra in grado di fare tutti i tipi di calcoli: nel tuo caso potresti farlo| awk '$1>100'
Andrea

4
@fionbio Sembra che non puoi usare -c e -d insieme su OSX uniq . Grazie per averlo segnalato. Puoi usare grep per filtrare linee uniche :sort FILE | uniq -c | grep -v '^ *1 '
Andrea

72

Per trovare e contare le linee duplicate in più file, puoi provare il seguente comando:

sort <files> | uniq -c | sort -nr

o:

cat <files> | sort | uniq -c | sort -nr

30

attraverso :

awk '{dups[$1]++} END{for (num in dups) {print num,dups[num]}}' data

Al awk 'dups[$1]++'comando, la variabile $1contiene l'intero contenuto di column1 e le parentesi quadre sono l'accesso alla matrice. Pertanto, per ogni prima colonna della riga nel datafile, il nodo dell'array denominato dupsviene incrementato.

E alla fine, eseguiamo il looping dupssull'array con numcome variabile e stampiamo prima i numeri salvati , quindi il loro numero di valore duplicato dups[num].

Si noti che il file di input ha spazi alla fine di alcune righe, se si cancellano quelli, è possibile utilizzare $0 al posto del $1comando sopra :)


1
Non è un po 'eccessivo considerando che abbiamo uniq?
Nathan Fellman,

9
sort | uniqe la soluzione awk presenta compromessi di prestazioni e risorse piuttosto diversi: se i file sono grandi e il numero di righe diverse è piccolo, la soluzione awk è molto più efficiente. È lineare nel numero di linee e l'utilizzo dello spazio è lineare nel numero di linee diverse. OTOH, la soluzione awk deve conservare tutte le diverse linee in memoria, mentre l'ordinamento (GNU) può ricorrere a file temporanei.
Lars Noschinski,

14

In Windows usando "Windows PowerShell" ho usato il comando menzionato di seguito per raggiungere questo obiettivo

Get-Content .\file.txt | Group-Object | Select Name, Count

Inoltre possiamo usare il cmdlet where-object per filtrare il risultato

Get-Content .\file.txt | Group-Object | Where-Object { $_.Count -gt 1 } | Select Name, Count

puoi cancellare tutte le occorrenze dei duplicati tranne l'ultimo ... senza cambiare l'ordinamento del file?
jparram,

6

Supponendo di avere accesso a una shell Unix standard e / o all'ambiente cygwin:

tr -s ' ' '\n' < yourfile | sort | uniq -d -c
       ^--space char

Fondamentalmente: converti tutti i caratteri dello spazio in interruzioni di riga, quindi ordina l'output tradotto e alimentalo in uniq e conta le righe duplicate.

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.