Suchen Sie nach doppelten Spaltenwerten in CSV

Suchen Sie nach doppelten Spaltenwerten in CSV

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 sortGNU 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\nwird 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-sedVersion 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 PerlLö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

verwandte Informationen