Spaltenweises Vergleichen von Dateien unter Unix

Spaltenweises Vergleichen von Dateien unter Unix

Ich möchte zwei Dateien mit gleicher Zeilen- und Spaltenanzahl und Datensätzen in gleicher Reihenfolge vergleichen. Ich möchte lediglich die Unterschiede in den Spaltenwerten hervorheben, falls welche vorhanden sind.

file A:

1,kolkata,19,ab

2,delhi,89,cd

3,bangalore,56,ef

file B:

1,kolkata,21,ab

2,mumbai,89,gh

3,bangalore,11,kl

Wenn wir die Spalte 1als Primärschlüssel betrachten, gibt es Unterschiede in anderen Spalten. Ich möchte diese Unterschiede hervorheben.

Das Ausgabeformat könnte sein (nicht sicher):

record_number,  columns_with_diff
1               3

2               2,4

3               3,4

Kann diffoder commkann das mein Problem lösen? Wenn ja, wie lautet der genaue Befehl?

Antwort1

Das wäre es. Nur ein Stilproblem mit dem zusätzlichen Komma am Ende jeder Zeile.

awk '
     BEGIN{ FS=","; ORS="" }

     { 
       # read line from secondary file
       getline aux < "file2"
       split(aux,f2,",")

       # print current line number
       print NR" "

       # process each field in current line
       for(i=1; i<=NF; i++) {
         if ($i!=f2[i]) {
           print i","
         }
       }
       print "\n"
     }
' file1

Die Ausgabe:

1 3,
2 2,4,
3 3,4,

Antwort2

Einfacher geht es mit perl:

$ perl -F',' -anle '
    BEGIN{
        print "record_number,  columns_with_diff";
        $" = ",";
    }
    if (!defined($h{$.})) {
        @{$h{$.}}{0..$#F} = @F[0..$#F];
    } else {
        @diff =  grep { $h{$.}{$_} ne $F[$_] } 0..$#F;
        print "$.\t\t@{[map {$_+1} @diff]}";
    } 
    close ARGV if eof;
' file1 file2
record_number,  columns_with_diff
1       3
2       2,4
3       3,4

Damit dies funktioniert, sollten Sie Leerzeilen in Ihrer Eingabe entfernen.

Erläuterung

  • Im BEGINBlock drucken wir einfach den Header der Ausgabe und setzen dann den Listentrenner auf,

  • @{$h{$.}}{0..$#F} = @F[0..$#F]: Wir erstellen einen Hash aus Hashes, wobei die Schlüssel des ersten Hashes die Zeilennummer sind, die Schlüssel jedes Unter-Hashes der Index des Felds minus 1 sind und die Werte Werte sind, die mit diesen Feldern korrespondieren.

Hier verwenden wir ein Hash-Slice, um Hashes von Hashes schnell Werte zuzuweisen.

Wenn Sie Data::Dumperden Hash der Hashes drucken %h, sehen Sie ungefähr Folgendes:

VAR1 = {
          '2' => {
                   '2' => '89',
                   '0' => '2',
                   '1' => 'delhi',
                   '3' => 'cd'
                 },
          '3' => {
                   '1' => 'bangalore',
                   '3' => 'ef',
                   '0' => '3',
                   '2' => '56'
                 },
          '1' => {
                   '3' => 'ab',
                   '1' => 'kolkata',
                   '0' => '1',
                   '2' => '19'
                 }
        };
  • %hWenn wir ( ) erstellt haben if (!defined($h{$.}))– also die Verarbeitung abgeschlossen haben file1– vergleichen wir einfach jedes Feld der aktuellen Zeile mit dem entsprechenden Wert in %hund speichern alle Indizes, die sich im Array unterscheiden @diff. map {$_+1} @diffStellen Sie die Spaltennummer wieder her, da der Index des Arrays bei 0 und die Spaltennummer bei 1 beginnt.

  • close ARGV if eofZähler wiederherstellen $..

verwandte Informationen