Dlaczego uniq nie jest na tyle wyjątkowy, że istnieje również uniq --unique?


35

Oto polecenia dotyczące losowego pliku z 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

Strony podręcznika nie są jasne, co -urobi flaga. Jakakolwiek rada?


4
Spróbuj posortować | uniq -d | wc -l i możesz zauważyć różnicę. :)
stoeff

Odpowiedzi:


42

Krótka wersja:

  • uniq, bez -u, sprawia, że ​​każdy wiersz wyniku jest unikalny.
  • uniq -udrukuje tylko każdą unikalną linię z wejścia .

Nieco dłuższa wersja:

uniqsłuży do obsługi plików, które mają zduplikowane linie i tylko wtedy, gdy linie te pojawiają się kolejno na wejściu. Zatem dla swoich celów unikalna linia to taka, która nie jest natychmiast duplikowana.

( uniqma bardzo ograniczoną pamięć krótkotrwałą; nigdy nie będzie pamiętał, czy linia pojawiła się wcześniej na wejściu, chyba że była to bezpośrednio poprzednia linia - dlatego uniqbardzo często jest łączona sort).

Gdy napotka szereg powtarzających się wierszy, uniqbez -uargumentu drukuje jedną kopię tego wiersza. (To sprawia, że ​​każdy wiersz wyniku jest unikalny ).

Z -uargumentem wypisuje zero kopii tego wiersza - serie duplikatów są po prostu pomijane w danych wyjściowych.


1
Naprawdę chciałbym, aby istniała opcja niewymagająca sortowania. Wymagałoby to jednak przechowywania całego pliku w pamięci (lub wykonywania dużej liczby księgowań za pomocą skrótów i przesunięć, jeśli źródłem jest normalny plik)
Random832

3
@ Random832: i wymagałoby podjęcia decyzji, które z duplikatów zachować (najpierw, ostatnie, coś innego, konfigurowalne), a ta decyzja wpłynęłaby na algorytm globalnie. Kłopot.
Steve Jessop

1
@ Random832: jeśli chodzi o liczbę znaków do wpisania, możesz użyć sort -uzamiast sort | uniq.
oliver

@oliver Od czasu do czasu chciałem mieć możliwość zachowania pierwszej instancji dowolnej linii bez zmiany jej kolejności i pisania skryptów, aby to zrobić.
Random832

1
@hvd: jeśli twoja wersja uniqzawiera normalizację i zestawianie, tak. Ale nawet wtedy jest to tylko kwestia lokalna - wiesz, gdzie w posortowanym wyjściu pojawi się linia, i po prostu musisz wybrać, którą z kilku sąsiednich linii zachować. Jeśli dane wejściowe nie zostaną posortowane, decyzja wpłynie na całą operację unifikacji, na przykład jeśli zamierzasz zachować ostatni duplikat, nie możesz wyprowadzić niczego, dopóki nie przeczytasz ostatniego wiersza danych wejściowych ...
Steve Jessop,

53

uniqz -upomija wszystkie linie, które mają duplikaty. A zatem:

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

Zwykle uniqdrukuje wiersze co najwyżej raz (przy założeniu posortowanego wejścia). Ta opcja faktycznie drukuje wiersze, które są naprawdę unikalne (nie pojawiły się ponownie).


11
Oznacza to, że uniqmożna nazwać distinct, ponieważ drukuje wszystkie odrębne linie, natomiast uniq -udrukuje wszystkie unikalne linie.
Steve Jessop,

W niektórych lokalizacjach nie jest to naprawdę wyjątkowe z GNU uniq.
cuonglm

Musiałem czytać zaakceptowaną odpowiedź kilka razy, ale ona nie wpadła. Twój przykład i akapit po niej wyjaśniają (i wracając i ponownie czytając zaakceptowaną odpowiedź, też to rozumiem) :)
Madivad

18

specyfikacja uniq POSIX wyraźnie to opisała:

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

-uopcja powoduje, aby uniqnie drukować powtarzających się linii.

Większość uniqimplementacji używała porównania bajtów, podczas gdy GNU uniqstosowało porządek sortowania do filtrowania zduplikowanych linii. Może więc powodować nieprawidłowe wyniki w niektórych lokalizacjach, na przykład w en_US.UTF-8ustawieniach regionalnych:

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

i nie -udał ci żadnych wierszy:

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

Powinieneś więc ustawić ustawienia regionalne, Caby uzyskać porównanie bajtów:

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

3
Należy pamiętać, że to, co jest nie tak tutaj nie jest tak dużo uniq(choć najwyraźniej intencją POSIX, że powinno to zrobić porównanie bajtów zamiast strcoll () porównanie jak w sort -u) jako tych lokalizacjach, które błędnie mają ① sortowania taka sama jak ②. Przynajmniej GNU uniqjest zgodny z sort -u.
Stéphane Chazelas,

@ StéphaneChazelas - gdzie w specyfikacji jest to widoczne?
mikeserv

O uniqkonieczności zrobienia memcmp / strcmp w przeciwieństwie do strcoll, co nie jest dla mnie zbyt oczywiste, ale dotyczyło Geoffa . O tym, że ustawienia narodowe GNU mają ① sortowanie takie same jak ②, jest to oczywiście błąd, ponieważ nie ma powodu, dla którego powinny sortować to samo. Jest to dozwolone przez POSIX, ale nadchodzą pewne zmiany .
Stéphane Chazelas,

8

normalna:

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

uniq: nie ma dwóch kolejnych powtarzających się wierszy

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

posortowane

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

sort -u: nie ma dwóch powtarzających się wierszy

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

sort / uniq: wszystkie odrębne

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

liczy różne wystąpienia

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

tylko wiersze, które się nie powtarzają (nie są najpierw sortowane)

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

tylko wiersze, które się nie powtarzają (po sortowaniu)

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

uniq -d: wypisuje tylko zduplikowane linie, po jednej dla każdej grupy

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

.. policzył

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

ładne jasne przykłady :)
Madivad,
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.