
Das Löschen von Duplikaten mit awk ist ziemlich üblich und einfach. Aber ich muss nur die Zeilen drucken, die dupliziert sind, wenn wir nur eine Spalte vergleichen. Ich habe diesen Befehl ausprobiert:
awk 'seen[$2]++'
aber wie Sie sehen, hat es Mängel. Es druckt Duplikate, aber erst seit ihrem zweiten Auftreten. Ich habe gerade erst angefangen, mich an Unix und Bash zu gewöhnen, daher wäre es toll, wenn Sie mir die Lösung erklären könnten.
Antwort1
Ich sehe zwei Möglichkeiten, dies zu tun:
Durchlaufen Sie die Datei zweimal:
Zählen Sie in der ersten Iteration, wie oft jedes $2 vorkommt.
Drucken Sie in der zweiten Iteration nur die Zeilen, bei denen die Anzahl größer als 1 ist.awk 'NR == FNR {count[$2]++; next} count[$2] > 1' file file
mit einer einzigen Iteration der Daten:
Sie müssen zählen, wie oft jeder $2 vorkommt,UndMerken Sie sich, welche Zeilen für jeweils 2 $ aufgetreten sind.
Diese Antwort verwendet GNU awk für Arrays von Arrays. Die Reihenfolge der Ausgabe stimmt wahrscheinlich nicht mit der der Eingabedaten überein. Außerdem muss die gesamte Datei im Speicher gespeichert werden.
gawk ' { lines[$2][++count[$2]] = $0 } END { for (x in lines) if (count[x] > 1) for (i=1; i<=count[x]; i++) print lines[x][i] } ' file
Getestet mit Eingabedatei:
$ cat file
a b
b b
c b
a c
a d
b d
a e
und erwartete Ausgabe
a b
b b
c b
a d
b d
Antwort2
Unter Verwendung derselben Beispieleingabe wieGlenn Jackman's Antwort
$ awk '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' file
a b
b b
c b
a d
b d
!seen[$2]++
wenn$2
es vorher noch nicht aufgetreten ist:fl[$2]=$0
Speichern Sie diese erste Zeile. Ich bin davon ausgegangen, dass die Eingabe nicht sortiert ist und Duplikate überall in der Datei auftreten können. Daher speichere ich sie basierend auf$2
statt nur einer temporären Variable.c[$2]=1
In ähnlicher Weise initialisieren Sie die Variable count mit 1
$2 in seen
wenn$2
schon einmal aufgetreten:if(c[$2]--){print fl[$2]}
zuerst die vorherige Zeile drucken, der Zähler wird dekrementiert, so dass die Bedingung für nachfolgende Übereinstimmungen fehlschlägtprint
dann drucken Sie die aktuelle Zeile
Mit einigen anderen Eingaben
$ cat ip.txt
6.2 : 897 : bar
3.1 : 32 : foo
1.2 : 123 : xyz
2.3 : 32 : baz
7.5 : 897 : boo
$ awk -F: '$2 in seen{if(c[$2]--){print fl[$2]} print} !seen[$2]++{fl[$2]=$0; c[$2]=1}' ip.txt
3.1 : 32 : foo
2.3 : 32 : baz
6.2 : 897 : bar
7.5 : 897 : boo
Beachten Sie, dass die Reihenfolge davon abhängt, wie Duplikate auftreten
Antwort3
Wenn Sie zweimal über dieselbe Datei iterieren, können Sie Zeilennummern als praktische Indizes verwenden. Dies kann zu einer übersichtlicheren Logik führen.
awk 'NR == FNR {if ($2 in z) { y[z[$2]]; y[FNR] } z[$2]=FNR; next} (FNR in y)' file file
Ich habe bei meiner Antwort auf diese Frage einen ähnlichen Trick verwendet:
Dieser Trick beruht darauf, dass Awk eine Variable einfach durch Referenzieren erstellt und die index in arrayname
Konstruktion „true“ oder „false“ zurückgibt, je nachdem, ob ein Array-Element mit dem angegebenen Index erstellt wurde.