Care este diferența dintre “ sort -u ” și “ sort | uniq ”?

Oriunde văd pe cineva care are nevoie să obțină o listă sortată, unică, se conectează întotdeauna la sort | uniq. „Nu am văzut niciodată exemple în care cineva folosește sort -u în schimb. De ce nu? Care este diferența și de ce este mai bine să folosiți uniq decât steagul unic pentru a sorta?

Comentarii

Răspuns

sort | uniq exista înainte ca sort -u și este compatibil cu o gamă mai largă de sisteme, deși aproape toate sistemele moderne acceptă -u – este POSIX. Este în mare parte o revenire până în zilele în care sort -u nu exista (iar oamenii nu au tendința de a-și schimba metodele dacă modul în care știu continuă să funcționeze, uitați-vă la ifconfig vs. ip adoptare).

Probabil că cele două au fost îmbinate, deoarece eliminarea duplicatelor dintr-un fișier necesită sortare (cel puțin, în standard este un caz de utilizare extrem de obișnuit. De asemenea, este mai rapid intern ca urmare a faptului că puteți face ambele operații în același timp (și datorită faptului că nu necesită IPC între uniq și sort). Mai ales dacă fișierul este mare, sort -u va folosi probabil mai puține fișiere intermediare pentru a sorta datele.

Pe sistemul meu Obțin în mod constant rezultate de acest fel:

$ 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 

De asemenea, nu maschează codul de returnare al sort, care poate fi important (în cochilii moderni există modalități de a obține acest lucru, de exemplu, bash „s $PIPESTATUS, dar acest lucru nu a fost” t întotdeauna adevărat).

Comentarii

  • Tind să folosesc sort | uniq deoarece de 9 ori din 10, De fapt, ‘ mă duc la uniq -c.
  • Rețineți că sort -u a făcut parte din ediția a 7-a UNIX, circa 1979. Versiunile sort withou Asistența pentru -u sunt cu adevărat arhaice – sau au fost scrise fără atenție la standardul de facto înainte de POSIX ‘ s de jure standard. A se vedea, de asemenea, Stack Overflow Sortare & uniq în Linux shell din 2010.
  • +1 pentru că din ip. Este ‘ s 2016 și această postare în 2013, dar știu doar despre comanda ip acum.
  • +1 pentru ” de 9 ori 10 I ‘ m canalizând de fapt către uniq -c ” (și poate încă o dată canalizarea către sort -nr | head). Mă întrebam care este echivalentul sort | uniq în Vim când am aflat că Vim are comanda :sort u. Și TIL sort -u există, de asemenea.
  • Rețineți că există o diferență atunci când utilizați sort -n | uniq vs. sort -n -u. De exemplu, spațiile albe de urmărire și de conducere vor fi văzute ca duplicate de sort -n -u, dar nu de primul! echo -e 'test \n test' | sort -n -u returnează test, dar echo -e 'test \n test' | sort -n | uniq returnează ambele linii.

Răspuns

O diferență este că uniq are o serie de opțiuni suplimentare utile, cum ar fi sărind câmpuri pentru comparație și numărând numărul de repetări ale unei valori. sort „s -u implementează doar funcționalitatea comenzii uniq fără ornamente.

Comentarii

  • +0.49 pentru un răspuns util, dar aș spune-o ceva de genul ” sort -u nu se poate transmite ‘ la uniq pentru a utiliza unele dintre acestea din urmă ‘ opțiuni utile, cum ar fi sări peste câmpuri pentru comparație și numărarea numărului de repetări. ”
  • +1 pentru a compensa naysayers, deoarece ” nu există ‘ nici o modalitate de a face acest lucru direct din sortare ” răspunde la întrebare …

Răspuns

Cu POSIX sort s și uniq s (GNU uniq în prezent nu este conformă în acest sens), există o diferență prin faptul că sort folosește algoritmul de asociere local pentru a compara șirurile (de obicei se va folosi strcoll() pentru a compara șirurile) în timp ce uniq verifică identitatea valorii octeților (va folosi de obicei strcmp()) ¹.

Acest lucru contează din cel puțin două motive .

  • În unele locații, în special pe sistemele GNU, există diferite caractere care sortează la fel. De exemplu, în localizarea en_US.UTF-8 pe un sistem GNU, toate ①②③④⑤⑥⑦⑧⑨⑩ … caracterele² și multe altele sortează la fel, deoarece ordinea lor de sortare nu este definită. 0123456789 cifre arabe sortează la fel ca Eastern Arabic Indic (s).

    Pentru sort -u, ① sortează la fel ca ② și 0123 la fel ca ٠١٢٣, astfel încât sort -u ar păstra doar unul din fiecare, în timp ce pentru uniq (nu GNU uniq care folosește strcoll() (cu excepția -i)), ① este diferit din ② și 0123 diferit de ٠١٢٣, deci uniq ar considera toate cele 4 unice.

  • strcoll poate compara șiruri de caractere valide (comportamentul este nedefinit conform POSIX atunci când intrarea are secvențe de octeți care nu formează caractere valide) în timp ce strcmp() nu-i pasă despre caractere, deoarece face doar comparație octet-la-octet. Deci, acesta este un alt motiv pentru care sort -u poate să nu vă ofere toate liniile unice dacă unele dintre ele nu formează un text valid. sort|uniq, deși încă nespecificat la introducerea fără text, în practică este mai probabil să vă ofere linii unice din acest motiv.

În afară de aceste subtilități, un lucru care nu a fost remarcat până acum este că uniq compară linia întreagă lexical, în timp ce sort „s -u compară pe baza specificațiilor de sortare date pe linia de comandă.

$ 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 

¹ Versiunile anterioare ale specificației POSIX au provocat confuzie, însă prin listarea variabilei LC_COLLATE ca una care afectează uniq, care a fost eliminată în ediția din 2018 și comportamentul clarificat în urma acelei discuții menționate mai sus. Consultați eroarea de grup Austin corespunzătoare

² 2019 editați . Cele de atunci au fost remediate, dar peste 95% din punctele de cod Unicode au încă o ordine nedefinită începând cu versiunea 2.30 a GNU libc . Puteți testa cu 🧙🧚🧛🧜🧝, de exemplu, în versiunile mai noi

Răspunde

Prefer să folosesc sort | uniq deoarece atunci când încerc să folosesc opțiunea -u (eliminați duplicatele) pentru a elimina duplicatele care implică șiruri de litere mari, nu este atât de ușor să înțelegeți rezultatul.

Notă: înainte de a putea rula exemplele de mai jos, trebuie să simulați secvența standard de asamblare C făcând următoarele:

LC_ALL=C export LC_ALL 

De exemplu, dacă vreau să sortez un fișier și să elimin duplicatele, păstrând în același timp diferitele cazuri de șiruri.

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

Această confuzie este rezolvată prin utilizarea opțiunii -u pentru a elimina duplicatele. Utilizarea uniq este mai previzibilă. Mai jos, mai întâi sortează și ignoră cazul și apoi îl trimite la uniq pentru a elimina duplicatele.

$ sort -f short | uniq Apple apple Pear pear 

Comentarii

  • -u opțiunea sort generează primul de o alergare egală (vezi pagina man). Astfel, sort -fu preia prima apariție a fiecărei linii unice insensibile la majuscule. Logica pe care sort o folosește pentru a elimina duplicatele este previzibilă.

Răspuns

O altă diferență pe care am aflat-o astăzi este când sortez pe baza unui delimetru unde sort -u aplică steagul unic numai pe coloana cu care sortați.

$ 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 

Comentarii

  • Acest lucru este menționat într-un răspuns de la St é phane Chazelas, dar Îmi place exemplul dvs., așa că +1
  • Vă mulțumim că ați subliniat @roaima, nu a fost ‘ foarte clar în acest răspuns

Lasă un răspuns

Adresa ta de email nu va fi publicată. Câmpurile obligatorii sunt marcate cu *