Wie ist uniq nicht so einzigartig, dass es auch uniq --unique gibt?

35

Hier sind Befehle für eine zufällige Datei aus dem 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

In den Manpages ist nicht klar, was die -uFlagge tut. Irgendein Rat?

Faszination
quelle
4
Versuchen Sie sort | uniq -d | wc -l und du könntest den Unterschied erkennen. :)
stoeff

Antworten:

42

Kurzfassung:

  • uniqOhne -umacht jede Zeile der Ausgabe einzigartig.
  • uniq -udruckt nur jede einzelne Zeile aus der Eingabe .

Etwas längere Version:

uniqDient zum Behandeln von Dateien, deren Zeilen dupliziert wurden, und nur dann, wenn diese Zeilen nacheinander in der Eingabe erscheinen. Aus diesem Grund ist eine eindeutige Zeile eine Zeile, die nicht sofort dupliziert wird.

( uniqhat ein sehr begrenztes Kurzzeitgedächtnis; es wird sich nie daran erinnern, ob eine Zeile früher in der Eingabe erschienen ist, es sei denn, es war die unmittelbar vorhergehende Zeile - aus diesem Grund uniqwird sie sehr oft gepaart sort.)

Wenn es auf eine Reihe doppelter Zeilen stößt, uniqwird ohne das -uArgument eine Kopie dieser Zeile gedruckt . (Es macht jede Zeile der Ausgabe einzigartig ).

Mit dem -uArgument werden keine Kopien dieser Zeile ausgegeben - Dublettenfolgen werden einfach in der Ausgabe weggelassen.

Ian Clelland
quelle
1
Ich wünschte wirklich, es gäbe eine Option, die keine Sortierung erfordert. Aber es würde erfordern, die gesamte Datei im Speicher zu halten (oder viel Buchhaltung mit Hashes und Offsets zu
betreiben,
3
@ Random832: und es müsste entschieden werden, welche der Dupes aufbewahrt werden sollen (zuerst, zuletzt, etwas anderes, konfigurierbar), und diese Entscheidung würde sich global auf den Algorithmus auswirken. Ärger.
Steve Jessop
1
@ Random832: Wenn es nur um die Anzahl der einzugebenden Zeichen geht, können Sie sort -ustatt verwenden sort | uniq.
Oliver
@oliver Ich wollte gelegentlich die Möglichkeit haben, die erste Instanz einer Zeile zu behalten, ohne sie neu anzuordnen, und habe dazu Skripte geschrieben.
Random832,
1
@hvd: Wenn Ihre Version von uniqNormalisierung und Sortierung ausführt , ja. Aber selbst dann ist es nur eine lokale Überlegung - Sie wissen, wo in der sortierten Ausgabe die Zeile erscheint, und müssen nur auswählen, welche von mehreren benachbarten Zeilen beibehalten werden soll. Wenn die Eingabe nicht sortiert ist, wirkt sich die Entscheidung auf den gesamten Vorgang der Vereinheitlichung aus. Wenn Sie beispielsweise das letzte Duplikat behalten, können Sie erst dann etwas ausgeben, wenn Sie die letzte Zeile der Eingabe gelesen haben ...
Steve Jessop
53

uniqmit werden -ualle doppelt vorhandenen Zeilen übersprungen. Somit:

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

Normalerweise werden uniqZeilen höchstens einmal gedruckt (bei sortierter Eingabe). Diese Option druckt tatsächlich Zeilen, die wirklich einzigartig sind (nicht mehr aufgetaucht sind).

muru
quelle
11
Das heißt, uniqkönnte aufgerufen werden distinct, da alle unterschiedlichen Zeilen uniq -ugedruckt werden, während alle eindeutigen Zeilen gedruckt werden.
Steve Jessop
In manchen Ländern ist es mit GNU nicht wirklich einzigartiguniq .
Dienstag,
Ich muss die akzeptierte Antwort ein paarmal gelesen haben, aber sie ist nicht aufgegangen. Ihr Beispiel und Absatz danach machen es sehr deutlich (und wenn ich die akzeptierte Antwort noch einmal lese, verstehe ich das auch) :)
Madivad
18

uniq POSIX spec hat es klar beschrieben:

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

-uOption machen uniq, um wiederholte Zeilen nicht zu drucken.

Die meisten uniqImplementierungen verwendeten den Byte-Vergleich, während GNU uniqdie Sortierreihenfolge verwendete, um doppelte Zeilen zu filtern. So kann es in einigen Gebietsschemas zu falschen Ergebnissen kommen, zum Beispiel im en_US.UTF-8Gebietsschema:

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

und -ugab dir keine Zeilen:

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

Deshalb sollten Sie das Gebietsschema auf setzen C, um einen Byte-Vergleich zu erhalten:

$ printf '%b\n' '\U2460' '\U2461' | LC_ALL=C uniq
①
②
cuonglm
quelle
3
Beachten Sie, dass hier nicht so viel falsch ist uniq(obwohl POSIX anscheinend die Absicht hatte, einen Byte-Vergleich anstelle von strcoll () als in durchzuführen), wie dies bei sort -uGebietsschemata der Fall ist, bei denen ① fälschlicherweise wie ② sortiert wird. Zumindest ist GNU uniqkonsistent mit sort -u.
Stéphane Chazelas
@ StéphaneChazelas - wo in der Spezifikation wird das deutlich gemacht?
mikeserv
Über uniqerforderlich, um memcmp / strcmp im Gegensatz zu strcoll zu tun, ist das für mich nicht sehr offensichtlich, aber das war für Geoff . Bezüglich der GNU-Gebietsschemata, in denen ① wie ② sortiert ist, ist dies eindeutig ein Fehler, da es keinen Grund gibt, warum sie gleich sortiert werden sollten. Das ist von POSIX erlaubt, aber es gibt einige Änderungen .
Stéphane Chazelas
8

normal:

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

uniq: keine zwei aufeinanderfolgenden sich wiederholenden Zeilen

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

sortiert

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

sort -u: keine zwei sich wiederholenden Zeilen

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

sort / uniq: alle verschieden

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

zählt verschiedene Vorkommen

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

nur Zeilen, die nicht wiederholt werden (nicht zuerst sortiert)

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

nur Zeilen, die nicht wiederholt werden (nach dem Sortieren)

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

uniq -d: druckt nur doppelte Zeilen, eine für jede Gruppe

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

.. gezählt

echo "a b a b c c c" | tr ' ' '\n' | uniq -dc
3 c
jmullee
quelle
schöne klare Beispiele :)
Madivad