Eu tenho dois arquivos que são delimitados por pipe e podem ter correspondências de coluna 1 + coluna 2 em ambos, ou um arquivo pode ter a entrada enquanto o outro não. Suponha que minha chave de correspondência seja igual a $ 1"-" $ 2 usando um pipe '|' como o FS.
arquivo1
1111|AAA|foo|50
1111|BBB|foo|30
2222|BBB|foo|10
arquivo2
1111|AAA|bar|10
1111|CCC|bar|20
3333|AAA|bar|40
A saída desejada seria a seguinte para a primeira entrada (eu tenho isso funcionando)
1111|AAA|50|10
Para a segunda entrada arquivo1 (se não houver coluna1+coluna2 correspondente em ambos os arquivos, substitua a entrada que está faltando para foo como 0. E vice-versa)
1111|BBB|30|0
E para uma chave de entrada (coluna1+coluna2) no arquivo2, mas não no arquivo1 (esta é a entrada 3 da saída esperada do arquivo 2)
3333|AAA|0|40
Assim, o formato geral de saída desejado está listando TODAS as chaves exclusivas que são representadas por column1+column2 em AMBOS os arquivos. Com as entradas da 3ª coluna sendo os valores do arquivo1 coluna 4 (ou 0 se o valor não existir no arquivo1) e a 4ª coluna na saída como os valores na coluna 4 do arquivo 2 (ou 0 se o valor não existir no arquivo2 ).
Eu fiz muitas pesquisas e tentei muitas coisas, mas tenho valores que não são exibidos se o par column1+column2 existir no arquivo2, mas não no arquivo1, usando o seguinte:
join -t"|" -e0 -a1 -a2 -o 1.2,1.3,1.5,2.5 <(<file1 awk -F"|" '{print $1"-"$2"|"$0}' | sort -k1,1) <(<file2 awk -F"|" '{print $1"-"$2"|"$0}' | sort -k1,1)
O caso acima me dá a saída esperada se houver uma correspondência de coluna1+coluna2 no arquivo1, mas não no arquivo2, e acrescenta um 0 para a correspondência não existente... Como posso fazer isso funcionar para TODOS os cenários?
O comando acima fará alguma substituição de processo adicionando uma chave na coluna 1 em ambos os arquivos que é column1+column2 e, em seguida, unirá com base nessa nova chave. -e0 adicionará um 0 se esta chave existir no arquivo1, mas não no arquivo2. Como posso fazê-lo cobrir o caso de: Nova chave (coluna1-coluna2) existe no arquivo 2, mas NÃO no arquivo 1?
Com sua abordagem, você deve usar
join
duas vezes (ou alterar sua abordagem para fazê-lo com uma únicajoin
invocação ):file1
comjoin -t'|' -e0 -a1 -o 1.2,1.3,1.5,2.5 <(<file1 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1) <(<file2 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1)
file2
comjoin -t'|' -e0 -v2 -o 2.2,2.3,1.5,2.5 <(<file1 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1) <(<file2 awk -F'|' '{print $1"-"$2"|"$0}' | sort -t'|' -k1,1)
Você pode fazer o mesmo com uma única
awk
invocação, armazenando$4
em dois arrays indexados por, por exemplo$1|$2
, e então noEND
bloco iterando sobre cada array de índices, comparando-os e imprimindo de acordo:Outra
awk
abordagem:Explicação:
NR==FNR{f1[$1FS$2]=$NF;next}
, isso será executado apenas para o arquivo1 e com a combinação de teclas$1FS$2
armazenará o último valor da coluna$NF
no array chamadof1
(FS
substituirá pelo Field S eperator|
do awk ) .{f2[$1FS$2]=$NF}
, igual ao anterior, mas será executado apenas para file2for (x in f1){print x,f1[x],f2[x]?f2[x]:0; delete f2[x]}
, faça um loop dentro da matrizf1
e imprima a chave (x
), seu valor no arquivo1f1[x]
e se houver a mesma chave do arquivo1 no arquivo2, imprima também, senão imprima0
(condição ternária usadaf2[x]?f2[x]:0
), depois disso também estamos excluindo o registro da mesma chave do arquivo2 comdelete f2[x]
.for (y in f2) print y, 0, f2[y]
, agora o arrayf2
tem registros que existem apenas no arquivo2, então estamos imprimindo a chave (y
),0
porque não existe no arquivo1 e seu valor no arquivo2f2[y]
.O seguinte substitui o primeiro
|
em ambos os arquivos por@
(use um caractere que não ocorra em outro lugar no arquivo), executa ojoin
e, em seguida, altera de@
volta para o original|
. Dessa forma, criamos um novo|
campo de junção delimitado consistindo nas colunas 1 e 2 dos arquivos originais.Na especificação do campo de saída (
-o
), um zero representa o campo de junção e a coluna 3 em qualquer arquivo é, na verdade, a coluna 4 dos dados originais.Para os arquivos de entrada fornecidos, isso gera