Befehl, der den Wert nur einmal druckt, obwohl er viele Male erscheint

8

Ich habe eine große txt-Datei, in der sich die Werte viele Male wiederholen. Gibt es einen Befehl, den ich verwenden kann, der die Datei durchläuft, und wenn ein Wert einmal angezeigt wird, wiederholen Sie ihn nicht erneut?

SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
SO4
HOH
CL
BME
HOH
SO4
HOH
CL
BME
HOH
CL

Es sollte also ungefähr so ​​aussehen:

S04   
HOH  
CL   
BME 

Die Sache ist, dass ich eine große Anzahl verschiedener Werte habe, also kann ich es nicht manuell wie hier machen.

djordje
quelle

Antworten:

11

Sie können den Befehl sortmit der folgenden Option verwenden --unique:

sort -u input-file

Wenn Sie das Ergebnis anstelle der Standardausgabe in die DATEI schreiben möchten, verwenden Sie die folgende Option --output=FILE:

sort -u input-file -o output-file

Der Befehl kann uniqauch angewendet werden. In diesem Fall müssen die identischen Zeilen folgen , daher muss die Eingabe vorläufig sortiert werden - danke an @RonJohn für diesen Hinweis:

sort input-file | uniq > output-file

Ich mag den sortBefehl für ähnliche Fälle wegen seiner Einfachheit, aber wenn Sie mit großen Arrays arbeiten, könnte der awkAnsatz aus der Antwort von John1024 leistungsfähiger sein. Hier ist ein Zeitvergleich zwischen den genannten Ansätzen, der auf eine Datei (basierend auf dem obigen Beispiel) mit fast 5 Millionen Zeilen angewendet wird:

$ cat input-file | wc -l
20000000

$ TIMEFORMAT=%R
$ time sort -u input-file | wc -l
64
7.495

$ time sort input-file | uniq | wc -l
64
7.703

$ time awk '!a[$0]++' input-file | wc -l      # from John1024's answer
64
1.271

$ time datamash rmdup 1 < input-file | wc -l  # from αғsнιη's answer
64
0.770

Ein weiterer wesentlicher Unterschied ist der von @Ruslan erwähnte :

sort -udruckt das Ergebnis erst, wenn die Eingabe beendet ist, während dieser awkBefehl jede neue Ergebniszeile im laufenden Betrieb druckt (dies ist möglicherweise wichtiger für Pipeline-Eingaben als für Dateien).

Hier ist eine Illustration:

Geben Sie hier die Bildbeschreibung ein

Im obigen Beispiel erzeugt die Schleife (unten gezeigt) 500 zufällige Kombinationen der Buchstaben AD mit einer Länge von jeweils drei Zeichen. Diese Kombinationen werden an awkoder weitergeleitet sort.

for i in {1..500}; do cat /dev/urandom | tr -dc A-D | head -c 3; echo; done
pa4080
quelle
1
Es ist ein sehr einfacher Befehl! Danke vielmals! Alles Gute.
Djordje
2
Oh, für die Tage, als ein Dienstprogramm eine Sache tat und es gut machte !! sort input-file | uniq!!!!
RonJohn
15

Wenn Sie die Ausgabezeilen in derselben Reihenfolge wie die Eingabezeilen halten möchten, verwenden Sie:

$ awk '!a[$0]++' file
SO4
HOH
CL
BME

Wie es funktioniert:

Dies verwendet ein assoziatives Array, um azu zählen, wie oft jede Zeile zuvor gesehen wurde. Wenn es vorher nicht gesehen wurde, wird die Zeile gedruckt.

John1024
quelle
2
Es ist sehr schwierig awk, aber es sort -uist der einfache Weg.
Pierre François
4
@ PierreFrançois, ist aber sort -uauch der langsamste Weg :) Ich habe meine Antwort mit einem Zeitvergleich zwischen den beiden Ansätzen aktualisiert.
pa4080
4
Außerdem sort -uwird das Ergebnis erst gedruckt, wenn die Eingabe beendet ist, während dieser awkBefehl jede neue Ergebniszeile im laufenden Betrieb druckt (dies ist möglicherweise wichtiger für die Weiterleitung als für die Datei).
Ruslan
Danke für diesen Hinweis, @Ruslan! Ich habe versucht, es in meiner Antwort zu veranschaulichen.
pa4080
Ich muss gestehen, dass die awkLösung sehr gut ist, wenn auch nicht so einfach zu lesen wie sort.
Pierre François
1

Sie können GNU datamash hier auch wie folgt verwenden und behalten die Zeilenreihenfolge bei.

datamash rmdup 1 < infile
αғsнιη
quelle
1
Nach dem time Vergleich ist dies die schnellste Lösung, die hier angeboten wird.
pa4080