Vad är skillnaden mellan “ sort -u ” och “ sort | uniq ”?

Överallt där jag ser någon behöver få en sorterad, unik lista, rör de alltid till sort | uniq. Jag har aldrig sett några exempel där någon använder sort -u istället. Varför inte? Vad är skillnaden, och varför är det bättre att använda uniq än den unika flaggan för att sortera?

Kommentarer

Svar

sort | uniq fanns innan sort -u, och är kompatibel med ett bredare utbud av system, även om nästan alla moderna system stöder -u – det är POSIX. Det är oftast en throwback till de dagar då sort -u inte fanns (och människor inte tenderar att ändra sina metoder om det sätt som de vet fortsätter att fungera, titta bara på ifconfig vs. ip antagande).

De två slogs sannolikt samman eftersom borttagning av dubbletter i en fil kräver sortering (åtminstone i standarden fall), och är ett extremt vanligt användningsfall. Det går också snabbare internt som ett resultat av att man kan utföra båda operationerna samtidigt (och på grund av att det inte kräver IPC mellan uniq och sort). Speciellt om filen är stor kommer sort -u sannolikt att använda färre mellanfiler för att sortera data.

På mitt system Jag får konsekvent resultat så här:

$ 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 

Det maskerar inte heller returkoden för sort kan vara viktigt (i moderna skal finns det sätt att få detta, till exempel bash ”s $PIPESTATUS array, men det här var inte alltid sant).

Kommentarer

  • Jag brukar använda sort | uniq för 9 gånger av 10, Jag ’ jag rör faktiskt till uniq -c.
  • Observera att sort -u var en del av 7: e upplagan UNIX, cirka 1979. Versioner av sort withou stöd för -u är verkligen arkaiska – eller skrevs utan uppmärksamhet mot de facto-standarden innan POSIX ’ s de jure-standarden. Se även Stack Overflow Sortera & uniq i Linux-skal från 2010.
  • +1 eftersom av ip. Det ’ s 2016 och det här inlägget 2013, men jag vet bara om ip kommandot nu.
  • +1 för ” 9 gånger ut 10 I ’ jag rör faktiskt till uniq -c ” (och kanske rör igen en gång till sort -nr | head). Jag undrade vad som motsvarar sort | uniq i Vim när jag fick reda på att Vim har :sort u -kommando. Och TIL sort -u finns också.
  • Observera att det finns en skillnad när du använder sort -n | uniq vs. sort -n -u. Till exempel kommer efterföljande och ledande vita utrymmen att ses som dubbletter av sort -n -u men inte av den förra! echo -e 'test \n test' | sort -n -u returnerar test, men echo -e 'test \n test' | sort -n | uniq returnerar båda raderna.

Svar

En skillnad är att uniq har ett antal användbara ytterligare alternativ, till exempel hoppa över fält för jämförelse och räkna antalet repetitioner av ett värde. sort ”s -u -flaggan implementerar endast funktionaliteten för det oskönade uniq -kommandot. p>

Kommentarer

  • +0.49 för ett användbart svar, men jag skulle uttrycka det ungefär som ” Utdata från sort -u kan ’ t skickas till uniq för att använda några av de senare ’ s användbara alternativ, som att hoppa över fält för jämförelse och räkna antalet repetitioner. ”
  • +1 för att kompensera naysayers eftersom ” där ’ är inget sätt att göra detta direkt från sortering ” svarar på frågan …

Svar

Med POSIX-kompatibel sort s och uniq s (GNU uniq är för närvarande inte kompatibel i det avseendet), där ”är en skillnad genom att sort använder lokalens sorteringsalgoritm för att jämföra strängar (använder vanligtvis strcoll() för att jämföra strängar) medan uniq söker efter bytevärdeidentitet (kommer vanligtvis att använda strcmp()) ¹.

Det är viktigt av minst två skäl .

  • I vissa språk, särskilt på GNU-system, finns det olika tecken som sorterar lika. Till exempel, i en_US.UTF-8-platsen på ett GNU-system sorterar alla ①②③④⑤⑥⑦⑧⑨⑩ … tecken² och många andra samma eftersom deras sorteringsordning inte är definierad. De arabiska siffrorna 0123456789 sorterar samma som deras Eastern Arabic Indic motsvarigheter (٠١٢٣٤٥٦٧٨٩).

    För sort -u, ① sorterar samma som ② och 0123 samma som ٠١٢٣ så sort -u behåller bara en av vardera, medan för uniq (inte GNU uniq som använder strcoll() (utom med -i)), ① är annorlunda från ② och 0123 skiljer sig från ٠١٢٣, så uniq anser att alla 4 är unika.

  • strcoll kan bara jämföra strängar med giltiga tecken (beteendet är odefinierat enligt POSIX när ingången har sekvenser av byte som inte bildar giltiga tecken) medan strcmp() inte bryr sig om karaktärer eftersom det bara gör byte-till-byte-jämförelse. Så det är en annan anledning till att sort -u kanske inte ger dig alla unika rader om vissa av dem inte utgör giltig text. sort|uniq, medan det fortfarande är ospecificerat vid icke-textinmatning, är det i praktiken mer sannolikt att du får unika rader av den anledningen.

Förutom dessa finesser är en sak som hittills inte har noterats att uniq jämför hela raden lexiskt, medan sort ”s -u jämförs baserat på sorteringsspecifikationen som anges på kommandoraden.

$ 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 

¹ Tidigare versioner av POSIX-specifikationen orsakade förvirring men genom att lista LC_COLLATE variabel som en som påverkar uniq, som togs bort i 2018-upplagan och beteendet klargjordes efter den diskussion som nämnts ovan. Se motsvarande Austin-gruppbugg

² 2019 redigera . De har sedan dess fixats, men över 95% av Unicode-kodpunkter har fortfarande en odefinierad ordning från version 2.30 av GNU libc . Du kan testa med 🧙🧚🧛🧜🧝 istället till exempel i nyare versioner

Svar

Jag föredrar att använda sort | uniq för när jag försöker använda alternativet -u (eliminera dubbletter) är det inte så lätt att ta bort dubbletter med blandade fallsträngar förstå resultatet.

Obs! Innan du kan köra exemplen nedan måste du simulera standard C-sorteringssekvensen genom att göra följande:

LC_ALL=C export LC_ALL 

Till exempel om jag vill sortera en fil och ta bort dubbletter samtidigt som jag håller olika fall av strängar olika.

$ 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?) 

Denna förvirring löses genom att inte använda alternativet -u för att ta bort dubbletter. Att använda uniq är mer förutsägbart. Nedan sorterar först och ignorerar fallet och skickar det sedan till uniq för att ta bort dubbletterna.

$ sort -f short | uniq Apple apple Pear pear 

Kommentarer

  • -u alternativet för sort matar ut första av en lika körning (se man sida). Således sort -fu tar upp den första förekomsten av varje skiftlägeskänslig unik linje. Logiken som sort använder för att ta bort dubbletter är förutsägbar.

Svar

En annan skillnad som jag fick reda på idag är när jag sorterar baserat på en avgränsare där sort -u bara tillämpar den unika flaggan i kolumnen som du sorterar med.

$ 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 

Kommentarer

  • Detta nämns i ett svar från St é phane Chazelas men Jag gillar ditt exempel så +1
  • Tack för att du påpekade @roaima, det var inte ’ t mycket tydligt i det svaret

Lämna ett svar

Din e-postadress kommer inte publiceras. Obligatoriska fält är märkta *