Mesclando dois arquivos de texto usando AWK

Mesclando dois arquivos de texto usando AWK

Não tenho muita experiência no awk, então luto para superar um problema com ele. Tenho dois arquivos chamados arquivo1.txt e arquivo2.txt. Arquivo1.txt:

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

Arquivo2.txt:

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

Sempre existem 4 valores após as duas primeiras colunas em cada um dos arquivos.

O que estou tentando fazer é mesclar esses arquivos em um só. Estou me juntando a eles pela primeira e segunda colunas.

No arquivo resultante deve haver 10 colunas. As duas primeiras são a chave, as próximas 4 colunas são valores do primeiro arquivo e as 4 últimas são do segundo.

No arquivo resultante, cada registro do primeiro arquivo que não corresponda ao segundo arquivo (e vice-versa) terá zeros adicionais que representam os valores ausentes.

Tudo é separado por caracteres de espaço em branco.

O resultado deve ficar assim:

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 é o meu script awk que modifiquei de um que encontrei enquanto pesquisava na 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  }                           
}

O resultado é classificado pela segunda coluna e todos os valores ausentes são preenchidos com zeros. No entanto, o resultado que estou obtendo atualmente é assim:

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

Apesar do arquivo não estar classificado (sempre posso usar sort -k 2), algumas das linhas não são impressas da maneira pretendida e não consigo explicar por que normalmente ele não consegue imprimir o elemento de um A variedade. Eu tentei várias coisas, como alterar temporariamente o ORS (sem saída) ou usar print em vez de printf (o resultado também parece estranho).

Devido à falta de experiência, isso levanta algumas questões adicionais:

É razoável usar o awk para concluir esta tarefa? Eu tentei usarjuntar, mas acabou travando porque não foi possível imprimir a coluna com um caractere de nova linha no final. Talvez um script Python seja mais útil?

Considerando que usarei arquivos muito grandes para mesclar, é razoável usar arrays em termos de memória?

Desde já, obrigado!

Responder1

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

isso funcionará enquanto houver memória suficiente para carregar o primeiroarquivo1na memória.

No primeiro bloco !second {...}, que só roda quando é o primeiro arquivo e carregamos oarquivo1em uma matriz associada no par de 1ª ecolunas como as chaves da matriz.

No segundo bloco second {...}, que só é executado quando for o segundo arquivo, imprimimos as linhas unidas aquelas que possuem chaves correspondentes em ambos os arquivos, caso contrário, imprimimos as chaves e 0s seguidos pelo restante das colunas dearquivo2; então também excluímos as chaves do array com delete file1vals[$1 FS $2]as quais suas chaves existiam em ambos os arquivos.

No último bloco no END, imprimimos as chaves não correspondentes restantes relacionadas aarquivo1.

informação relacionada