Salta al contenuto principale

sort e uniq: ordina un testo e togli i duplicati

Inviato da tuxsa il

sort ordina le righe di un testo e uniq elimina quelle ripetute. Presi singolarmente sono utili; usati insieme formano una delle combinazioni più classiche del terminale, quella che permette di contare quante volte compare ogni elemento in un elenco o in un file di log.

Cos'è

sort significa "ordina" e uniq è l'abbreviazione di "unique", "unico". Entrambi fanno parte del pacchetto GNU coreutils e sono eseguibili (/usr/bin/sort e /usr/bin/uniq), presenti su qualsiasi distribuzione GNU/Linux.

Cosa fanno

  • sort legge le righe di uno o più file, o dello standard input, e le stampa in ordine. Di default l'ordine è alfabetico, secondo le regole della lingua del sistema.
  • uniq stampa le righe eliminando le ripetizioni, ma con una regola importante: toglie solo i duplicati adiacenti, cioè consecutivi. Per questo viene quasi sempre preceduto da sort, che porta vicine le righe uguali.

Nessuno dei due modifica i file di partenza: scrivono il risultato a schermo, o dove lo reindirizzi.

Come si usano

Sintassi base:

$ sort [opzioni] [file...]
$ uniq [opzioni] [file_in_ingresso [file_in_uscita]]

Per gli esempi usiamo un file frutta.txt con dieci righe, in cui alcuni nomi si ripetono:

$ cat frutta.txt
mele
pere
banane
mele
arance
pere
mele
banane
pere
mele

Esempio 1: ordinare con sort

$ sort frutta.txt
arance
banane
banane
mele
mele
mele
mele
pere
pere
pere

Con -r (reverse) l'ordine è invertito:

$ sort -r frutta.txt

Esempio 2: ordinare i numeri con -n

Di default i numeri sono ordinati come se fossero testo, cifra per cifra. Il file punti.txt contiene i valori 10, 9, 100, 25 e 2:

$ sort punti.txt
10
100
2
25
9
$ sort -n punti.txt
2
9
10
25
100

Con -n (numeric) i valori sono confrontati come numeri, e l'ordine è quello che ci si aspetta.

Esempio 3: ordinare le dimensioni con -h

L'opzione -h (human-numeric) riconosce i suffissi come K, M e G, e va d'accordo con l'output di du -h:

$ du -sh * | sort -h
4,0K    note.txt
120K    relazione.pdf
2,3M    intervista.mp3
1,1G    video

Esempio 4: ordinare per colonna con -t e -k

Con -t si indica il carattere che separa i campi e con -k la colonna da usare come chiave. Nel file utenti.txt ogni riga ha un nome e un'età separati da due punti:

$ cat utenti.txt
mario:42
anna:35
luca:28
$ sort -t: -k2 -n utenti.txt
luca:28
anna:35
mario:42

Il file è ordinato per età, cioè per il secondo campo, in senso numerico. Lo stesso metodo vale per i file di sistema: sort -t: -k3 -n /etc/passwd li ordina per identificativo utente.

Esempio 5: ordinare ed eliminare i duplicati con -u

$ sort -u frutta.txt
arance
banane
mele
pere

L'opzione -u (unique) fa in un colpo solo ciò che si otterrebbe con sort | uniq.

Esempio 6: salvare il risultato sullo stesso file con -o

$ sort -o frutta.txt frutta.txt

Con -o si può scrivere il risultato nel file di partenza in tutta sicurezza. Se invece usassi sort frutta.txt > frutta.txt, la shell svuoterebbe il file prima che sort lo legga, e perderesti tutto il contenuto: lo stesso errore visto per cat.

Esempio 7: uniq da solo non basta

Poiché uniq toglie solo le righe consecutive, sul file non ordinato non cambia nulla, perché nessuna riga è uguale alla precedente:

$ uniq frutta.txt
mele
pere
banane
mele
arance
pere
mele
banane
pere
mele

Dopo un ordinamento, invece, funziona come ci si aspetta:

$ sort frutta.txt | uniq
arance
banane
mele
pere

Esempio 8: contare le ripetizioni con uniq -c

$ sort frutta.txt | uniq -c
      1 arance
      2 banane
      4 mele
      3 pere

L'opzione -c (count) antepone a ogni riga il numero di volte in cui compariva.

Esempio 9: solo i duplicati o solo gli unici

$ sort frutta.txt | uniq -d
banane
mele
pere
$ sort frutta.txt | uniq -u
arance

Con -d (duplicates) si stampano le righe che compaiono più di una volta, una sola volta ciascuna; con -u (unique) solo quelle che compaiono una volta sola.

Esempio 10: la classifica delle frequenze

Aggiungendo un secondo sort, in senso numerico e inverso, si ottiene una classifica dall'elemento più frequente al meno frequente:

$ sort frutta.txt | uniq -c | sort -nr
      4 mele
      3 pere
      2 banane
      1 arance

È lo schema sort | uniq -c | sort -nr, da ricordare a memoria. Con head in coda si limita la classifica ai primi risultati. Per esempio, per sapere quali estensioni di file sono più diffuse nella tua cartella personale, puoi usare anche sed per isolare l'estensione:

$ find ~ -type f -name "*.*" | sed 's/.*\.//' | sort | uniq -c | sort -nr | head -n 3
    412 txt
    187 jpg
     96 pdf

Esempio 11: uso negli script

Unire due elenchi senza duplicati e trovare gli elementi presenti in entrambi:

#!/bin/bash
sort -u iscritti_a.txt iscritti_b.txt > iscritti_unione.txt
echo "Elementi unici: $(wc -l < iscritti_unione.txt)"

echo "Presenti in entrambi gli elenchi:"
{ sort -u iscritti_a.txt; sort -u iscritti_b.txt; } | sort | uniq -d

Nell'ultimo comando ogni elenco viene prima ripulito dai propri doppioni con sort -u. In questo modo una riga compare due volte solo se è presente in entrambi, e uniq -d la mostra.

Opzioni utili

Per sort:

  • -r: ordine inverso.
  • -n: ordine numerico; -h: numerico con suffissi (K, M, G).
  • -u: elimina le righe uguali dopo l'ordinamento.
  • -t carattere: separatore dei campi; -k N: ordina in base al campo N.
  • -f: ignora la differenza tra maiuscole e minuscole.
  • -o file: scrive il risultato nel file indicato, anche se coincide con l'ingresso.
  • -c: controlla se l'input è già ordinato, senza stampare nulla.
  • -V: ordina i numeri di versione in modo naturale (1.2, 1.10); -M: per mese.

Per uniq:

  • -c: mostra quante volte compare ogni riga.
  • -d: solo le righe ripetute; -u: solo quelle non ripetute.
  • -i: ignora maiuscole e minuscole nel confronto.
  • -f N: salta i primi N campi nel confronto.

Attenzione a

  • uniq vuole l'input ordinato: senza sort a monte, i duplicati non adiacenti non vengono rimossi.
  • L'ordine dipende dalla lingua del sistema: con le impostazioni italiane o inglesi sort non distingue chiaramente maiuscole e minuscole e trascura la punteggiatura; LC_ALL=C sort file usa invece l'ordine puro dei caratteri, con le maiuscole prima delle minuscole. Per script riproducibili, LC_ALL=C è spesso la scelta più sicura.
  • I numeri sono testo: senza -n, 100 viene prima di 2.
  • Mai sort file > file: svuota il file di partenza. Usa -o oppure un file temporaneo.
  • Righe "quasi" uguali: spazi finali e ritorni a capo di tipo Windows (^M) fanno apparire diverse righe che sembrano identiche. Con cat -A li scopri.
  • sort -u o uniq? Se ti basta eliminare i doppioni, sort -u è più breve. Se vuoi contare le ripetizioni o stampare solo duplicati o unici, serve uniq.
  • I campi con -k: di default il separatore è il passaggio da spazio a carattere non spazio. Con file separati da virgole o altri simboli ricordati di indicare -t.
  • File molto grandi: sort gestisce file più grandi della memoria usando file temporanei, ma lo spazio nella cartella /tmp deve bastare.

Riepilogo

ComandoCosa fa
sort fileOrdina le righe in ordine alfabetico
sort -r fileOrdine inverso
sort -n fileOrdine numerico
sort -hOrdine per dimensioni (K, M, G)
sort -t: -k2 fileOrdina per il secondo campo, separato da due punti
sort -u fileOrdina ed elimina i duplicati
sort -o f fOrdina scrivendo sullo stesso file
sort file | uniqElimina i duplicati
sort file | uniq -cConta le ripetizioni
sort file | uniq -dMostra solo le righe ripetute
sort | uniq -c | sort -nrClassifica per frequenza