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
-
FS
eOFS
são o separador do campo de entrada e o separador de campo de saída, respectivamente. (AparentementeIFS
não tem sentido emawk
; isso foi um erro da minha parte.) Você provavelmente não precisa doFS="\t"
-awk
reconhece 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, $4
e 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,4151
Se não incluirmos algum caractere separador na chave que não aparecem nos campos principais (MAIN1 e MAIN2), podemos obter o mesmo valor
key
para linhas diferentes. - Correndo o risco de dividir os cabelos, não estou dizendo nada ao Linux;
Estou dizendo
awk
o 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
=a
e$3
=sure3
, portantokey
=1,a
.present[key] = 1
significa que estou definindopresent["1,a"]
para1
como sinalizador para indicar quefile3
tem uma1,a
line; ou seja, que existe um valorminor9
parakey
=1,a
. Como não há5,a
linha emfile3
,present["5,a"]
não é definido, e assim a parte "file1 + file2
" do código sabe que não háminor9
parakey
=5,a
, e deve imprimir-
. O nomepresent
é apenas uma escolha arbitrária da minha parte; indica que a linha1,a
está presente emfile3
(e a linha5,a
não é). É convencional usar1
para representar "VERDADEIRO". -
Você pode substituir
print $1, $2, $3, $4
comfor (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.