Jaka jest różnica między “ sort -u ” a “ sort | uniq ”?

Wszędzie, gdzie widzę, że ktoś potrzebuje posortowanej, unikalnej listy, zawsze kieruje do sort | uniq. „Nigdy nie widziałem żadnych przykładów, w których ktoś zamiast tego używa sort -u. Dlaczego nie? Jaka jest różnica i dlaczego do sortowania lepiej jest użyć uniq niż unikalnej flagi?

Komentarze

Odpowiedź

sort | uniq istniał przed sort -u i jest kompatybilny z szerszą gamą systemów, chociaż prawie wszystkie współczesne systemy obsługują -u – to POSIX. To głównie powrót do czasów, kiedy sort -u nie istniało (a ludzie nie mają tendencji do zmiany swoich metod, jeśli znany im sposób nadal działa, spójrz na ifconfig a ip adopcja).

Oba zostały prawdopodobnie połączone, ponieważ usuwanie duplikatów w pliku wymaga sortowania (przynajmniej w standardzie przypadek) i jest niezwykle powszechnym przypadkiem użycia. Jest również szybszy wewnętrznie dzięki możliwości wykonywania obu operacji w tym samym czasie (i ponieważ nie wymaga IPC między uniq a sort). Zwłaszcza jeśli plik jest duży, sort -u prawdopodobnie użyje mniejszej liczby plików pośrednich do sortowania danych.

W moim systemie Ciągle otrzymuję takie wyniki:

$ 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 

Nie maskuje też kodu powrotu sort, który może być ważne (w nowoczesnych powłokach są sposoby, aby to uzyskać, na przykład tablica bash „s $PIPESTATUS, ale to nie było zawsze prawda).

Komentarze

  • Zwykle używam sort | uniq, ponieważ 9 razy na 10 I ' m faktycznie podłączam do uniq -c.
  • Pamiętaj, że sort -u był częścią 7.edycji UNIX, około 1979 roku. Wersje sort bez Obsługa -u jest naprawdę archaiczna – lub została napisana bez zwracania uwagi na faktyczny standard przed standardem POSIX ' de iure. Zobacz też Przepełnienie stosu Sortuj & uniq w powłoce Linuksa od 2010 r.
  • +1, ponieważ z ip. To ' rok 2016 i ten post z 2013 r., Ale teraz wiem tylko o poleceniu ip.
  • +1 dla ” 9 przekroczonych limitów czasu 10 I ' m w rzeczywistości podłączam do uniq -c ” (i być może jeszcze raz podłączam do sort -nr | head). Zastanawiałem się, jaki jest odpowiednik sort | uniq w Vimie, kiedy dowiedziałem się, że Vim ma polecenie :sort u. Istnieje również TIL sort -u.
  • Zauważ, że istnieje różnica między sort -n | uniq a sort -n -u. Na przykład końcowe i początkowe białe znaki będą postrzegane jako duplikaty przez sort -n -u, ale nie przez pierwsze! echo -e 'test \n test' | sort -n -u zwraca test, ale echo -e 'test \n test' | sort -n | uniq zwraca obie linie.

Odpowiedź

Jedyną różnicą jest to, że uniq ma wiele przydatnych dodatkowych opcji, takich jak pomijanie pól do porównania i zliczanie liczby powtórzeń wartości. Flaga sort „s -u implementuje tylko funkcjonalność niewykończonego polecenia uniq.

Komentarze

  • +0.49, aby uzyskać użyteczną odpowiedź, ale powiedziałbym coś w stylu ” Wynik sort -u nie może ' nie zostać przekazane do uniq, aby użyć drugiego ' użytecznych opcji, takich jak pomijanie pól do porównania i liczenie liczby powtórzeń. ”
  • +1 do naysayers, ponieważ ” tam ' nie ma możliwości zrobienia tego bezpośrednio z sortowania ” czy odpowiada na pytanie …

Odpowiedź

Ze zgodnym z POSIX sort s i uniq s (GNU uniq jest obecnie niezgodne w tym zakresie), jest różnica w tym, że sort używa algorytmu zestawiania ustawień regionalnych do porównywania ciągów (zazwyczaj używa strcoll() do porównywania ciągów), podczas gdy uniq sprawdza tożsamość wartości bajtowej (zazwyczaj używa strcmp()) ¹.

Ma to co najmniej dwa powody .

  • W niektórych lokalizacjach, szczególnie w systemach GNU, istnieją różne znaki, które sortują to samo. Na przykład w lokalizacji en_US.UTF-8 w systemie GNU wszystkie ①②③④⑤⑥⑦⑧⑨⑩ … znaki² i wiele innych są sortowane tak samo, ponieważ ich kolejność sortowania nie jest zdefiniowana. Cyfry arabskie 0123456789 są sortowane tak samo, jak ich odpowiedniki w wschodnio-arabskich i indyjskich (٠١٢٣٤٥٦٧٨٩).

    Dla sort -u, ① sortuje to samo co ②, a 0123 tak samo jak ٠١٢٣, więc sort -u zachowa tylko jeden z nich, podczas gdy dla uniq (nie GNU uniq, które używa strcoll() (z wyjątkiem -i)), ① jest inne od ② i 0123 różni się od ٠١٢٣, więc uniq uzna wszystkie 4 za unikalne.

  • strcoll może porównywać tylko ciągi prawidłowych znaków (zachowanie jest niezdefiniowane zgodnie z POSIX, gdy dane wejściowe zawierają sekwencje bajtów, które nie tworzą prawidłowych znaków), podczas gdy strcmp() nie ma znaczenia o znakach, ponieważ porównuje tylko bajt do bajtu. To „kolejny powód, dla którego sort -u może nie zawierać wszystkich unikalnych wierszy, jeśli niektóre z nich nie tworzą prawidłowego tekstu. sort|uniq, chociaż wciąż nieokreślony w przypadku wprowadzania nietekstowego, w praktyce jest bardziej prawdopodobne, że z tego powodu otrzymasz unikalne linie.

Oprócz tych subtelności, jedna rzecz, której dotychczas nie zauważono, to to, że uniq porównuje leksykalnie cały wiersz, podczas gdy sort „s -u porównuje na podstawie specyfikacji sortowania podanej w wierszu poleceń.

$ 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 

¹ Wcześniejsze wersje specyfikacji POSIX powodowały jednak zamieszanie, wymieniając zmienną LC_COLLATE jako zmienną wpływającą na uniq, która została usunięta w edycji 2018 i zachowanie wyjaśniło się po wspomnianej powyżej dyskusji. Zobacz odpowiedni błąd grupy Austin

² 2019 edytuj . Od tego czasu zostały one naprawione, ale ponad 95% punktów kodowych Unicode nadal ma niezdefiniowaną kolejność w wersji 2.30 biblioteki GNU libc . Zamiast tego możesz przetestować za pomocą 🧙🧚🧛🧜🧝, na przykład w nowszych wersjach

Odpowiedź

Wolę używać sort | uniq, ponieważ kiedy próbuję użyć opcji -u (eliminuj duplikaty), aby usunąć duplikaty zawierające ciągi znaków o różnych wielkościach, nie jest to takie łatwe zrozumieć wynik.

Uwaga: zanim uruchomisz poniższe przykłady, musisz zasymulować standardową kolejność zestawiania w C, wykonując następujące czynności:

LC_ALL=C export LC_ALL 

Na przykład, jeśli chcę posortować plik i usunąć duplikaty, jednocześnie zachowując różne przypadki ciągów znaków.

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

To zamieszanie można rozwiązać, nie używając opcji -u do usuwania duplikatów. Używanie uniq jest bardziej przewidywalne. Poniższy przykład najpierw sortuje i ignoruje wielkość liter, a następnie przekazuje ją do uniq w celu usunięcia duplikatów.

$ sort -f short | uniq Apple apple Pear pear 

Komentarze

  • -u opcja sort wyświetla pierwszy równego przebiegu (patrz strona podręcznika). W ten sposób sort -fu wybiera pierwsze wystąpienie każdego unikalnego wiersza bez rozróżniania wielkości liter. Logika, której sort używa do usuwania duplikatów, jest przewidywalna.

Odpowiedź

Inną różnicą, którą odkryłem dzisiaj, jest sortowanie na podstawie separatora, w którym sort -u stosuje unikalną flagę tylko do kolumny, według której sortujesz.

$ 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 

Komentarze

  • Wspomina o tym odpowiedź św. é phane Chazelas, ale Podoba mi się twój przykład, więc +1
  • Dziękuję za wskazanie @roaima, odpowiedź nie była ' bardzo jasna

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *