Crie os seguintes arquivos:
merge21 :
BEGIN {
FS = "\t"
OFS = "\t"
}
NR==FNR { # file2
key = $2 "," $3
present[key] = 1
minor8[key] = $1
next
}
{ # file1
key = $1 "," $3
if (present[key]) print $1, $2, $3, $4, minor8[key]
else print $1, $2, $3, $4, "-"
}
merge312 :
BEGIN {
FS = "\t"
OFS = "\t"
}
NR==FNR { # file3
key = $1 "," $2
present[key] = 1
minor9[key] = $3
next
}
{ # file1 + file2
key = $1 "," $3
if (present[key]) print $1, $2, $3, $4, $5, minor9[key]
else print $1, $2, $3, $4, $5, "-"
}
Eles são quase idênticos; Eu corrijo as diferenças. Agora digite o comando
awk -f merge21 file2 file1 | awk -f merge312 file3 -
Isso pressupõe que nenhum dos seus campos principais inclui vírgula (s)
e nenhum dos seus dados inclui hífens
mas realmente depende apenas de haver algumas strings
que não aparecem nos dados.
Seria trivial estender isso para suportar mais colunas;
Espero que isso seja óbvio.
Isso poderia ser aprimorado para fazer tudo em uma única execução de awk ,
mas isso seria um pouco mais complexo, e (IMNSHO) não vale o esforço.
Isso produz o que é chamado de "junção externa esquerda" dos dados em seus arquivos; consulte Diferença entre o INNER e o OUTER junta-se ao Stack Overflow para algumas definições. (“Junção externa esquerda” é definida na resposta aceita a essa pergunta como (parafraseada) «Todas as linhas na primeira tabela, mais quaisquer linhas comuns na (s) outra (s) tabela (s)».
Sua saída será
MAIN1 minor1 MAIN2 minor3 minor8 minor9
1 bla1 a blabla1 yes6 sure3
1 bla2 b blabla2 yes7 sure4
1 bla3 c blabla3 yes8 sure5
2 bla4 a blabla4 yes9 sure6
2 bla5 d blabla5 - sure7
3 bla6 e blabla6 yes2 sure8
4 bla7 f blabla7 yes3 sure9
5 bla8 a blabla8 yes4 -
5 bla9 g blabla9 yes5 sure2
e, obviamente, você pode remover os caracteres - com sed .
(E, claro, se os dados reais incluírem hífens,
escolha algum caractere não usado ou string como o espaço reservado para dados ausentes.)
Notas
-
FSeOFSsão o separador do campo de entrada e o separador de campo de saída, respectivamente. (AparentementeIFSnão tem sentido emawk; isso foi um erro da minha parte.) Você provavelmente não precisa doFS="\t"-awkreconhece guias como separadores de campo na entrada por padrão. (Permite que você tenha campos que contenham espaços, mas você não parece estar interessado nisso.)OFS="\t"é importante; por causa disso, eu posso dizerprint $1, $2, $3, $4e obtenha os campos de entrada para serem saída com abas entre eles. Se eu não dissesseOFS="\t", eles seriam separados por espaços, a menos que eu tenha ditoprint $1 "\t" $2 "\t" $3 "\t" $4, que é entediante e prejudica a legibilidade. -
Se você tivesse dado restrições adicionais a MAIN1 e MAIN2 - por exemplo, eles sempre têm apenas um caractere cada ou MAIN1 é sempre um número e MAIN2 sempre começa com uma letra - Eu não precisaria da vírgula (
,) emkey. Mas a versão original da sua primeira pergunta não mostra tal restrição. Considere os seguintes dados:MAIN1 ($2) MAIN2 ($3) badkey = $2 $3 goodkey = $2 "," $3 2 34151 234151 2,34151 23 4151 234151 23,4151Se não incluirmos algum caractere separador na chave que não aparecem nos campos principais (MAIN1 e MAIN2), podemos obter o mesmo valor
keypara linhas diferentes. - Correndo o risco de dividir os cabelos, não estou dizendo nada ao Linux;
Estou dizendo
awko que fazer. - Em relação ao código
NR==FNR { # file3 key = $1 "," $2 present[key] = 1 minor9[key] = $3 next }Considere a sétima da última linha defile3, que contém1 a sure3. Obviamente, temos$1=1,$2=ae$3=sure3, portantokey=1,a.present[key] = 1significa que estou definindopresent["1,a"]para1como sinalizador para indicar quefile3tem uma1,aline; ou seja, que existe um valorminor9parakey=1,a. Como não há5,alinha emfile3,present["5,a"]não é definido, e assim a parte "file1 + file2" do código sabe que não háminor9parakey=5,a, e deve imprimir-. O nomepresenté apenas uma escolha arbitrária da minha parte; indica que a linha1,aestá presente emfile3(e a linha5,anão é). É convencional usar1para representar "VERDADEIRO". -
Você pode substituir
print $1, $2, $3, $4comfor (n=1; n<=4; n++) printf "%s\t", $n. Você deve terminar a linha usando apenasprint(em oposição aprintf) para o último campo ou fazendoprintf "\n". Você pode simplificar ainda mais fazendo algo parecido comfor (n=1; n<=4; n++) printf "%s\t", $n if (present[key]) print minor8[key] else print "-"
Por favor, leia awk (1) , o Especificação de POSIX para awk ,
O Guia do Usuário do GNU Awk , e veja Awk.info para mais informações.