Wie erhält man nur die eindeutigen Ergebnisse, ohne Daten sortieren zu müssen?

40
$ cat data.txt 
aaaaaa
aaaaaa
cccccc
aaaaaa
aaaaaa
bbbbbb
$ cat data.txt | uniq
aaaaaa
cccccc
aaaaaa
bbbbbb
$ cat data.txt | sort | uniq
aaaaaa
bbbbbb
cccccc
$

Das Ergebnis, das ich brauche, ist die Anzeige aller Zeilen aus der Originaldatei, wobei alle Duplikate (nicht nur die aufeinanderfolgenden) entfernt werden, während die ursprüngliche Reihenfolge der Anweisungen in der Datei beibehalten wird .

Hier, in diesem Beispiel, war das Ergebnis, nach dem ich tatsächlich gesucht habe

aaaaaa
cccccc
bbbbbb

Wie kann ich diese verallgemeinerte uniqOperation im Allgemeinen ausführen ?

Laser
quelle

Antworten:

54
perl -ne 'print unless $seen{$_}++' data.txt

Oder, wenn Sie eine nutzlose Verwendung von haben müssencat :

cat data.txt | perl -ne 'print unless $seen{$_}++'

Hier ist eine awkÜbersetzung für Systeme, denen Perl fehlt:

awk '!seen[$0]++' data.txt
cat data.txt | awk '!seen[$0]++'
cjm
quelle
3
Ein etwas kürzeres awk-Skript ist{ if (!seen[$0]++) print }
camh
1
@fred, es sei denn, Ihre Datei ist wirklich riesig. Bei beiden Versionen dauert die Eingabe länger als die Ausführung.
cjm
8
Die awk - Version kann durch Weglassen der noch kürzer gemacht werden if, printsowie die Klammer und Klammern:awk '!seen[$0]++'
Gordon Davisson
2
@Legate, es ist der Name eines Arrays, in dem wir jede Zeile aufzeichnen, die wir gesehen haben. Sie könnten es '!LarryWall[$0]++'für alle awk Sorgen ändern , aber "gesehen" hilft den Leuten, das Programm besser zu verstehen.
cjm
1
@Sadi, das hätte eigentlich als Frage gestellt werden sollen, nicht als Kommentar. Einige der Zeilen in dieser Datei enden jedoch in einem Leerzeichen, andere nicht. Diese Befehle berücksichtigen die gesamte Zeile als wichtig, einschließlich des Leerzeichens am Ende.
cjm
13

John hat ein Tool namens unique:

usr@srv % cat data.txt | unique out
usr@srv % cat out
aaaaaa
cccccc
bbbbbb

Dasselbe ohne zusätzliche Tools in einer einzigen Befehlszeile zu erreichen, ist etwas komplexer:

usr@srv % cat data.txt | nl | sort -k 2 | uniq -f 1 | sort -n | sed 's/\s*[0-9]\+\s\+//'
aaaaaa
cccccc
bbbbbb

nlGibt Zeilennummern vor den Zeilen aus. Wenn wir sort/ uniqhinter ihnen stehen, können wir die ursprüngliche Reihenfolge der Zeilen wiederherstellen. sedlöscht nur die Zeilennummern danach;)

binfalse
quelle
Gibt es eine Kombination gebräuchlicher Linux-Befehle, die dasselbe bewirken könnten?
Lazer
7
Was haben Sie in "Ohne Daten sortieren" verpasst?
Totor
@Totor - Siehe die Antwort von menkus auf einen ähnlichen Kommentar. @binfalse - Ihre zweite Lösung funktioniert nicht (vielleicht funktioniert sie mit diesem einfachen Beispiel, aber mit einigen realen Eingaben funktioniert sie nicht). Bitte nl -ba -nrz data.txt | sort -k2 -u | sort | cut -f2
korrigieren
6

Ich bevorzuge dies zu verwenden:

cat -n data.txt | sort --key=2.1 -b -u | sort -n | cut -c8-

cat -n fügt Zeilennummern hinzu,

sort --key=2.1 -b -u Sortiert im zweiten Feld (nach den hinzugefügten Zeilennummern), ignoriert führende Leerzeichen und behält eindeutige Zeilen bei

sort -n Sortiert in strenger numerischer Reihenfolge

cut -c8- Bewahren Sie alle Zeichen von Spalte 8 bis EOL auf (dh lassen Sie die von uns angegebenen Zeilennummern weg).

menkus
quelle
5
> Wie erhält man nur die eindeutigen Ergebnisse, ohne Daten sortieren zu müssen? > ohne Daten sortieren zu müssen
Jan Wikholm
7
'ohne die Daten sortieren zu müssen' erscheint nur im Titel. Der eigentliche Bedarf besteht darin, "alle Zeilen aus der Originaldatei anzuzeigen und alle Duplikate (nicht nur die aufeinanderfolgenden) zu entfernen, während die ursprüngliche Reihenfolge der Anweisungen in der Datei beibehalten wird".
menkus
1
@menkus der Schlüssel ist "unter Beibehaltung der ursprünglichen Reihenfolge der Anweisungen in der Datei". Diese Antwort erreicht das nicht.
Andrew Ferrier
2

Perl verfügt über ein Modul, das Sie verwenden können und das eine aufgerufene Funktion enthält uniq. Wenn Sie also Ihre Daten in ein Array in Perl laden, rufen Sie einfach die folgende Funktion auf, um sie eindeutig zu machen, und behalten dennoch die ursprüngliche Reihenfolge bei.

use List::MoreUtils qw(uniq)    
@output = uniq(@output);

Weitere Informationen zu diesem Modul finden Sie hier: List :: MoreUtils

slm
quelle
Kann dies große Dateien verarbeiten, z. B. 500 GB?
Boy