ich versuche, doppelte IDs aus einer großen CSV-Datei zu finden. Es gibt nur einen Datensatz pro Zeile, aber die Bedingung zum Auffinden eines Duplikats ist die erste Spalte.<id>,<value>,<date>
beispiel.csv
11111111,high,6/3/2019
22222222,high,6/3/2019
33333333,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Gewünschte Ausgabe:
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Für die Ausgabe ist keine Reihenfolge erforderlich.
Antwort1
Verwenden von AWK:
awk -F, 'data[$1] && !output[$1] { print data[$1]; output[$1] = 1 }; output[$1]; { data[$1] = $0 }'
Dabei wird jede Zeile betrachtet und das Verhalten ist wie folgt:
- Wenn wir den Wert in der ersten Spalte bereits gesehen haben, beachten Sie, dass wir jede Zeile ausgeben sollten, die damit übereinstimmt, und die gespeicherte Zeile ausgeben sollten.
- Geben Sie die aktuelle Zeile aus, wenn ihre erste Spalte mit einer Spalte übereinstimmt, die wir ausgeben möchten.
- Speichern Sie die aktuelle Zeile anhand der ersten Spalte.
Antwort2
Wenn alle Ihre IDs die gleiche Länge haben (8 Zeichen in Ihrem Beispiel), können Sie das Ganze mit sort
GNU erledigen uniq
:
$ sort file | uniq -Dw 8
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Wenn sie nicht gleich lang sind, können Sie trotzdem diesen Ansatz verwenden, aber es wird etwas komplizierter:
$ tr ',' ' ' < file | sort | rev | uniq -f2 -D | rev | tr ' ' ','
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019
Antwort3
awk -F, '$1 in m { print m[$1]$0; m[$1]=""; next }
{ m[$1]=$0 "\n" }' ex
Antwort4
Dies kann durch die Verwendung der erweiterten Regex-Konstrukte erfolgen GNU sed
. Wir laden die Datei zuerst in den Musterbereich und entfernen dann alle nicht wiederholten Zeilen vom Anfang des Musterbereichs. Außerdem \n\n
wird am Ende des Musterbereichs eine Flagge platziert, mit der wir die wiederholten Zeilen löschen. Sobald diese Flagge also an den Anfang des Musterbereichs gelangt, ist der Vorgang abgeschlossen und wir können nun fortfahren und die Markierungen aus dem Musterbereich entfernen und auf stdout drucken.
$ sed -Ee '
$!{
N;s/^/\n/
$s/$/\n\n/;D
}
/^([^,\n]*),[^\n]*\n(.*\n)?\1,/!D
s/^([^\n]*)(.*)/\2\1\n/;/^\n\n/!D
s/^\n\n//;s/\n$//
' inp
Dies ist eine POSIX-sed
Version UND eine andere Möglichkeit, das Problem anzugehen, bei der wir die gesamte Datei zu keinem Zeitpunkt im Muster oder in den Haltebereichen beibehalten. Sobald eine doppelte Zeile erkannt wird, wird sie auf stdout gedruckt UND die Referenzzeile wird markiert und gedruckt, markiert, weil wir sie nicht drucken möchten, wenn das Duplikat das nächste Mal erkannt wird.
$ sed -ne '
H;g;y/\n_/_\n/
/.*_\([^,_]*\)\(,[^_]*\)\[0]_\(.*_\)\{0,1\}\1,[^_]*$/{
s//\1\2/;y/_\n/\n_/;p
g;s/.*\n//p;g;y/\n_/_\n/
s/\(.*_\([^,_]*\),[^_]*\)\[0]\(_\(.*_\)\{0,1\}\)\2,[^_]*$/\1[1]\3/
s/_$//;y/_\n/\n_/;bh
}
/.*_\([^,_]*\)\(,[^_]*\)\[1]_\(.*_\)\{0,1\}\1,[^_]*$/{
s/.*_//;y/_\n/\n_/;p
g;s/\(.*\)\n.*/\1/;bh
}
y/_\n/\n_/;s/$/[0]/;:h;h
' inp
Dies ist eine Perl
Lösung für das Problem, bei der wir die Zeilen in einem Hash-Array verwalten. Sobald wir eine sich wiederholende Zeile sehen, drucken wir das Array, leeren es und drucken auch die duplizierte Zeile.
$ perl -F, -lane '
push(@{$h{$F[0]}},$_),next if ! exists $h{$F[0]};
print for splice(@{$h{$F[0]}}),$_;
' inp
Ausgabe:
11111111,high,6/3/2019
11111111,low,5/3/2019
11111111,medium,7/3/2019