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ª e 2ª colunas 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.