Fusionar dos archivos de texto usando AWK

Fusionar dos archivos de texto usando AWK

No tengo mucha experiencia en awk, por lo que me cuesta superar un problema. Tengo dos archivos llamados file1.txt y file2.txt. Archivo1.txt:

20 101 1 2 3 4
20 102 5 6 7 8
20 108 3 3 3 3

Archivo2.txt:

20 100 99 99 99 99
20 101 11 22 33 44
20 103 55 66 77 88

Siempre hay 4 valores después de las dos primeras columnas en cada uno de los archivos.

Lo que intento hacer es fusionar estos archivos en uno solo. Me uno a ellos por la primera y segunda columnas.

En el archivo resultante debería haber 10 columnas. Las dos primeras son la clave, las siguientes 4 columnas son valores del primer archivo y las últimas 4 son del segundo.

En el archivo resultante, cada registro del primer archivo que no coincida con el segundo archivo (y viceversa) tendrá ceros adicionales que representan los valores faltantes.

Todo está separado por espacios en blanco.

El resultado debería verse así:

20 100 0 0 0 0 99 99 99 99
20 101 1 2 3 4 11 22 33 44
20 102 5 6 7 8 0 0 0 0
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0

Este es mi script awk que modifiqué a partir de uno que encontré mientras buscaba en la web:

BEGIN {                                                                                                                
   OFS=" "
}                                      
{                               
   i=$1 OFS $2 #Making key out of first and second field of the first file                    
}
   NR==FNR {                             
   A[i]=$0  #Saving records from first file to an array using first two columns as index                           
   next
}
#Next part assumes that I'm reading file2.txt                                         
i in A {                                
   printf "%s",A[i]  #Here, I have a match with first file, and I want to print the joined record I saved from file1.txt                                                                                               
   print $3,$4,$5,$6 #In order to print a joined record, after printing record from first file, I'm printing columns from the second file                                                                                           
   delete A[i]                           
   next
}

{ #Here I print records from file2.txt that don't have a match with file1.txt, and put zeroes to fill missing values
   print 0,0,0,0,$3,$4,$5,$6
}
END { #In the END block I'm printing everything from file1.txt that doesn't have a match and print zeroes aftewards to fill missing values
   for (i in A) {  printf "%s",A[i]; print 0,0,0,0  }                           
}

El resultado se ordena por la segunda columna y todos los valores faltantes se completan con ceros. Sin embargo, el resultado que obtengo actualmente se ve así:

20 100 0 0 0 0 99 99 99 99
11 22 33 443 4
20 103 0 0 0 0 55 66 77 88
20 108 3 3 3 3 0 0 0 0
0 0 0 0 6 7 8

A pesar de que el archivo no está ordenado (siempre puedo usar sort -k 2), algunas de las líneas no se imprimen de la forma prevista y no puedo explicar por qué normalmente no se puede imprimir el elemento de A. formación. Probé varias cosas, como cambiar temporalmente ORS (sin salida alguna) o usar print en lugar de printf (el resultado también parece extraño).

Debido a la falta de experiencia, esto plantea algunas preguntas adicionales:

¿Es razonable utilizar awk para completar esta tarea? He intentado usarunirse, pero finalmente se quedó atascado porque no podía imprimir la columna con un carácter de nueva línea al final. ¿Quizás un script de Python sea más útil?

Teniendo en cuenta que utilizaré archivos muy grandes para fusionar, ¿es razonable utilizar matrices en cuanto a memoria?

¡Gracias de antemano!

Respuesta1

awk '!second { file1vals[$1 FS $2]=$0 }
      second { print (($1 FS $2 in file1vals)?file1vals[$1 FS $2]: $1 FS $2 FS "0 0 0 0") FS $3, $4, $5, $6;
               delete file1vals[$1 FS $2]
             }
END{ for(x in file1vals) print file1vals[x], "0 0 0 0" }' file1 second=1 file2

esto funcionará siempre que haya suficiente memoria para cargar el primerarchivo1en la memoria.

En el primer bloque !second {...}, que solo se ejecuta cuando es el primer archivo y cargamos elarchivo1en una matriz asociada en el par de columnas 1ª ycomo claves para la matriz.

En el segundo bloque second {...}, que solo se ejecuta cuando es el segundo archivo, imprimimos las líneas unidas que tienen claves coincidentes en ambos archivos, de lo contrario imprimimos las claves y los 0 seguidos del resto de las columnas dearchivo2; luego también eliminamos las claves de la matriz con delete file1vals[$1 FS $2]la que sus claves existían en ambos archivos.

En el último bloque al FINAL, imprimimos las claves restantes que no coinciden relacionadas conarchivo1.

información relacionada