Qual è la differenza tra “sort -u” e “sort | uniq”?


120

Ovunque vedo qualcuno che ha bisogno di ottenere un elenco unico e ordinato, lo fanno sempre sort | uniq. Non ho mai visto esempi in cui qualcuno usa sort -uinvece. Perchè no? Qual è la differenza e perché è meglio utilizzare uniq rispetto al flag univoco per ordinare?


Risposte:


120

sort | uniqesisteva prima sort -ued è compatibile con una gamma più ampia di sistemi, sebbene quasi tutti i sistemi moderni supportino -u: è POSIX. È principalmente un ritorno ai giorni in cui sort -unon esistevano (e le persone non tendono a cambiare i loro metodi se il modo in cui sanno continuano a funzionare, basta guardare ifconfigcontro l' ipadozione).

I due sono stati probabilmente uniti perché la rimozione dei duplicati all'interno di un file richiede l'ordinamento (almeno, nel caso standard), ed è un caso di ordinamento estremamente comune. È inoltre più veloce internamente grazie alla possibilità di eseguire entrambe le operazioni contemporaneamente (e perché non richiede IPC tra uniqe sort). Soprattutto se il file è grande, sort -uprobabilmente utilizzerà meno file intermedi per ordinare i dati.

Sul mio sistema ottengo costantemente risultati come questo:

$ dd if=/dev/urandom of=/dev/shm/file bs=1M count=100
100+0 records in
100+0 records out
104857600 bytes (105 MB) copied, 8.95208 s, 11.7 MB/s
$ time sort -u /dev/shm/file >/dev/null

real        0m0.500s
user        0m0.767s
sys         0m0.167s
$ time sort /dev/shm/file | uniq >/dev/null

real        0m0.772s
user        0m1.137s
sys         0m0.273s

Inoltre non maschera il codice di ritorno di sort, che può essere importante (nelle shell moderne ci sono modi per ottenere questo, ad esempio, bashl' $PIPESTATUSarray, ma questo non è sempre stato vero).


31
Tendo a usarlo sort | uniqperché 9 volte su 10, sto effettivamente eseguendo il piping uniq -c.
Plutor,

5
Si noti che sort -ufaceva parte della 7a Edizione UNIX, intorno al 1979. Le versioni sortsenza supporto per -usono veramente arcaiche - o sono state scritte senza attenzione allo standard de facto prima dello standard de jure di POSIX. Vedi anche Stack Overflow Sort & uniq nella shell Linux dal 2010.
Jonathan Leffler,

3
+1 a causa di ip. È il 2016 e questo post nel 2013, ma ora conosco solo il ipcomando.
morto

4
+1 per "9 volte su 10 In realtà sto eseguendo il piping a uniq -c" (e forse il piping ancora una volta a sort -nr | head). Mi chiedevo quale fosse l'equivalente sort | uniqin Vim quando ho scoperto che Vim ha il :sort ucomando. E sort -uesiste anche TIL .
Zhuoyun Wei,

Si noti che v'è una differenza quando si usa sort -n | uniqcontro sort -n -u. Ad esempio, gli spazi bianchi finali e iniziali saranno visti come duplicati sort -n -uma non dal primo! echo -e 'test \n test' | sort -n -urestituisce test, ma echo -e 'test \n test' | sort -n | uniqrestituisce entrambe le righe.
mxmlnkn,

46

Una differenza è che uniqha una serie di utili opzioni aggiuntive, come saltare i campi per il confronto e contare il numero di ripetizioni di un valore. sortLa -ubandiera implementa solo la funzionalità del uniqcomando disadorno .


3
+0,49 per una risposta utile, ma la definirei come "L'output di sort -unon può essere passato uniqper utilizzare alcune delle utili opzioni di quest'ultimo, come saltare i campi per il confronto e contare il numero di ripetizioni".
10

15
+1 per compensare gli oppositori perché "non c'è modo di farlo direttamente da sort" fa rispondere alla domanda ...
Izkata

42

Con sorts e uniqs conformi a POSIX (GNU non uniqè attualmente conforme a tale riguardo), c'è una differenza nel fatto che sortutilizza l'algoritmo di fascicolazione delle impostazioni locali per confrontare le stringhe (in genere verrà utilizzato strcoll()per confrontare le stringhe) mentre uniqcontrolla l'identità del valore byte (in genere utilizzerà strcmp()) .

Ciò conta per almeno due motivi.

  • In alcune versioni locali, in particolare sui sistemi GNU, esistono caratteri diversi che ordinano lo stesso. Ad esempio, nella locale en_US.UTF-8 su un sistema GNU, tutti i caratteri ①②③④⑤⑥⑦⑧⑨⑩ ... e molti altri ordinano lo stesso perché il loro ordinamento non è definito. Le cifre arabe 0123456789 ordinano le stesse delle loro controparti Indie arabe orientali (٠١٢٣٤٥٦٧٨٩).

    Per sort -u, ① ordina lo stesso di ② e 0123 lo stesso di ٠١٢٣ quindi sort -umanterrebbe solo uno di ciascuno, mentre per uniq(non GNU uniqche usa strcoll()(tranne con -i)), ① è diverso da ② e 0123 diverso da ٠١٢٣, quindi uniqconsidererebbe tutto 4 unico.

  • strcollpuò confrontare solo stringhe di caratteri validi (il comportamento è indefinito come da POSIX quando l'input ha sequenze di byte che non formano caratteri validi) mentre strcmp()non si preoccupa dei caratteri poiché fa solo un confronto byte-to-byte. Quindi questo è un altro motivo per cui sort -upotresti non darti tutte le righe univoche se alcune di esse non formano un testo valido. sort|uniq, sebbene non ancora specificato sull'input non testuale, in pratica è più probabile che ti dia linee uniche per questo motivo.

Oltre a queste sottigliezze, una cosa che finora non è stata notata è che uniqconfronta l'intera linea in modo lessicale, mentre sorti -uconfronti si basano sulla specifica di ordinamento fornita sulla riga di comando.

$ printf '%s\n' 'a b' 'a c' | sort -uk 1,1
a b
$ printf '%s\n' 'a b' 'a c' | sort -k 1,1 | uniq
a b
a c

$ printf '%s\n' 0 -0 +0 00 '' | sort -n | uniq
0
-0
+0
00

$ printf '%s\n' 0 -0 +0 00 '' | sort -nu
0

9

Preferisco usare sort | uniqperché quando provo a usare l' -uopzione (elimina duplicati) per rimuovere duplicati che coinvolgono stringhe di maiuscole miste, non è così facile capire il risultato.

Nota: prima di poter eseguire gli esempi seguenti, è necessario simulare la sequenza di fascicolazione C standard procedendo come segue:

LC_ALL=C
export LC_ALL

Ad esempio, se voglio ordinare un file e rimuovere i duplicati, mantenendo allo stesso tempo distinti i diversi casi di stringhe.

$ cat short      #file to sort
Pear
Pear
apple
pear
Apple

$ sort short     #normal sort (in normal C collating sequence)
Apple            #the lower case words are at the end
Pear
Pear
apple
pear

$ sort -f short  #correctly sorts ignoring the C collating order
Apple            #but duplicates are still there
apple
Pear
Pear
pear

$ sort -fu short #By adding the -u option to remove duplicates it is 
apple            #difficult to ascertain the logic that sort uses to remove
Pear             #duplicates(i.e., why did it remove pear instead of Pear?)

Questa confusione viene risolta non usando l' -uopzione per rimuovere i duplicati. L'uso uniqè più prevedibile. Il seguente ordina prima e ignora il caso, quindi lo passa a uniqper rimuovere i duplicati.

$ sort -f short | uniq
Apple
apple
Pear
pear

2
-uopzione di sortoutput il primo di una corsa uguale (vedi pagina man). Quindi sort -furileva la prima occorrenza di ogni riga unica insensibile al maiuscolo / minuscolo. La logica che sortutilizza per rimuovere i duplicati è prevedibile.
Pallxk,

3

Un'altra differenza che ho scoperto oggi è quando l'ordinamento si basa su un delimitatore in cui viene sort -uapplicato il flag univoco solo sulla colonna con cui si ordina.

$ cat input.csv
3,World,1
1,Hello,1
2,Hello,1

$ cat input.csv | sort -t',' -k2 -u
1,Hello,1
3,World,1

$ cat input.csv | sort -t',' -k2 | uniq
1,Hello,1
2,Hello,1
3,World,1

Questo è menzionato in una risposta di Stéphane Chazelas ma mi piace il tuo esempio quindi +1
roaima

Grazie per aver sottolineato @roaima, non era molto chiaro in quella risposta
Stefanos Chrs
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.