Comparar archivos en Unix por columnas

Comparar archivos en Unix por columnas

Quiero comparar dos archivos con el mismo número de filas y columnas con registros en el mismo orden. Solo quiero resaltar las diferencias en los valores de las columnas, si las hay.

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

Considerando la columna 1como clave principal, tenemos diferencias en otras columnas. Quiero resaltar esas diferencias.

El formato de salida puede ser (no estoy seguro):

record_number,  columns_with_diff
1               3

2               2,4

3               3,4

¿Puede diffo commsolucionar mi problema? En caso afirmativo, ¿cuál sería el comando exacto?

Respuesta1

Esto sería todo. Sólo un problema de estilo con la coma adicional al final de cada línea.

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

La salida:

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

Respuesta2

Puedes hacerlo más fácil con 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

Debe eliminar las líneas en blanco en su entrada para que esto funcione.

Explicación

  • En BEGINel bloque simplemente imprimimos el encabezado de la salida, luego configuramos el separador de lista en,

  • @{$h{$.}}{0..$#F} = @F[0..$#F]: creamos un hash de hashes con las claves del primer hash que son el número de línea, cada subhashes tiene las claves que son el índice del campo menos 1 y los valores son valores que corresponden a esos campos.

Aquí usamos un segmento hash para asignar rápidamente valores al hash de hashes.

Si usas Data::Dumperpara imprimir el hash de hashes %h, puedes ver algo como esto:

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'
                 }
        };
  • Si hemos creado %h( if (!defined($h{$.}))), lo que significa que terminamos de procesar file1, simplemente comparamos cada campo de la línea actual con el valor de respuesta central %h, almacenando todos los índices diferentes en la matriz @diff. map {$_+1} @diffrestaure el número de columna, porque el índice de la matriz comienza en 0, el número de columna comienza en 1.

  • close ARGV if eofrestaurar $.contador.

información relacionada