In che modo uniq non è abbastanza unico da esistere anche uniq --unique?


35

Ecco i comandi su un file casuale da pastebin :

wget -qO - http://pastebin.com/0cSPs9LR | wc -l
350
wget -qO - http://pastebin.com/0cSPs9LR | sort -u | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq | wc -l
287
wget -qO - http://pastebin.com/0cSPs9LR | sort | uniq -u | wc -l
258

Le pagine man non sono chiare su cosa -ustia facendo la bandiera. Qualche consiglio?


4
Prova a ordinare | uniq -d | wc -l e potresti notare la differenza. :)
stoeff

Risposte:


42

Versione breve:

  • uniq, senza -u, rende unica ogni riga dell'output .
  • uniq -ustampa solo ogni riga univoca dall'input .

Versione leggermente più lunga:

uniqserve per gestire file con righe duplicate e solo quando tali righe appaiono in successione nell'input. Quindi, per i suoi scopi, una linea unica è quella che non viene duplicata immediatamente.

( uniqha una memoria a breve termine molto limitata; non ricorderà mai se una linea appariva prima nell'input, a meno che non fosse la riga immediatamente precedente - questo è il motivo per cui uniqmolto spesso è accoppiata sort.)

Quando incontra una serie di linee duplicate uniq, senza l' -uarg, stampa una copia di quella linea. (Rende unica ogni riga dell'output ).

Con l' -uargomento, stampa zero copie di quella riga - le serie di duplicati vengono semplicemente omesse dall'output.


1
Vorrei davvero che ci fosse un'opzione per non richiedere l'ordinamento. Ma richiederebbe di mantenere l'intero file in memoria (o fare un sacco di contabilità con hash e offset se l'origine è un file normale)
Casuale832

3
@ Random832: e richiederebbe decidere quale dei duplicati mantenere (primo, ultimo, qualcos'altro, configurabile) e quella decisione influenzerebbe l'algoritmo a livello globale. Problemi.
Steve Jessop,

1
@ Random832: se si tratta solo del numero di caratteri da digitare, è possibile utilizzare sort -uinvece di sort | uniq.
Oliver,

@oliver Occasionalmente desideravo avere la possibilità di mantenere la prima istanza di qualsiasi riga senza riordinarle, e script scritti per farlo.
Casuale 832

1
@hvd: se la tua versione di uniqnormalizzazione e regole di confronto, sì. Ma anche allora è solo una considerazione locale: sai dove apparirà la riga nell'output ordinato e devi solo selezionare quale delle diverse linee adiacenti mantenere. Se l'input non è ordinato, la decisione influisce sull'intera operazione di unificazione, ad esempio se manterrai l'ultimo duplicato, non puoi generare nulla fino a quando non leggi l'ultima riga dell'input ...
Steve Jessop,

53

uniqcon -usalta tutte le righe che hanno duplicati. Così:

$ printf "%s\n" 1 1 2 3 | uniq
1
2
3
$ printf "%s\n" 1 1 2 3 | uniq -u
2
3

Di solito, uniqstampa le righe al massimo una volta (presupponendo un input ordinato). Questa opzione in realtà stampa linee che sono davvero uniche (non sono più apparse).


11
Cioè, uniqpotrebbe essere chiamato distinct, poiché stampa tutte le linee distinte, mentre uniq -ustampa tutte le linee uniche.
Steve Jessop,

Non è veramente unico con GNU uniqin alcune impostazioni locali.
cuonglm,

Devo aver letto la risposta accettata diverse volte, ma non è andata a fondo. Il tuo esempio e il paragrafo dopo lo rendono molto chiaro (e tornando indietro e rileggendo la risposta accettata, ottengo anche quello) :)
Madivad,

18

Le specifiche uniq POSIX lo descrivono chiaramente:

-u
    Suppress the writing of lines that are repeated in the input.

-uopzione per uniqnon stampare righe ripetute.

La maggior parte delle uniqimplementazioni utilizzava il confronto dei byte, mentre GNU uniqutilizzava l'ordine di confronto per filtrare le linee duplicate. Quindi può produrre risultati errati in alcune impostazioni locali, ad esempio nelle impostazioni en_US.UTF-8locali:

$ printf '%b\n' '\U2460' '\U2461' | uniq
①

e -unon ti ha dato righe:

$ printf '%b\n' '\U2460' '\U2461' | uniq -u
<blank>

Quindi dovresti impostare le impostazioni locali Cper ottenere il confronto dei byte:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②

3
Si noti che ciò che è sbagliato qui non è tanto uniq(sebbene apparentemente l'intento di POSIX era che dovrebbe fare il confronto byte anziché il confronto strcoll () come in sort -u) di quei locali che erroneamente hanno ① l'ordinamento uguale a ②. Almeno GNU uniqè coerente con sort -u.
Stéphane Chazelas,

@ StéphaneChazelas - dove nelle specifiche è evidente?
Mikeserv,

A proposito di uniqdover fare memcmp / strcmp invece di strcoll, questo non è molto evidente per me, ma è stato per Geoff . Sulle localizzazioni GNU che hanno ① l'ordinamento uguale a ②, questo è chiaramente un bug in quanto non c'è motivo per cui dovrebbero ordinare lo stesso. Ciò è consentito da POSIX ma ci sono dei cambiamenti in arrivo .
Stéphane Chazelas,

8

normale:

echo "a b a b c c c" | tr ' ' '\n'
a
b
a
b
c
c
c

uniq: non ci sono due successive righe ripetute

echo "a b a b c c c" | tr ' ' '\n' | uniq
a
b
a
b
c

smistato

echo "a b a b c c c" | tr ' ' '\n' | sort
a
a
b
b
c
c
c

sort -u: non ci sono due righe ripetute

echo "a b a b c c c" | tr ' ' '\n' | sort -u
a
b
c

sort / uniq: tutti distinti

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq
a
b
c

conta occorrenze distinte

echo "a b a b c c c" | tr ' ' '\n' | sort | uniq -c
2 a
2 b
3 c

solo righe non ripetute (non ordinate per prime)

echo "a b a b c c c" | tr ' ' '\n' | uniq -u
a
b
a
b

solo righe non ripetute (dopo l'ordinamento)

echo "a b a b c c c Z" | tr ' ' '\n' | sort | uniq -u
Z

uniq -d: stampa solo righe duplicate, una per ciascun gruppo

echo "a b a b c c c" | tr ' ' '\n' | uniq -d
c

.. contato

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c

bei esempi chiari :)
Madivad,
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.