Unindo dois arquivos em um campo

1

Eu preciso comparar dois arquivos e, com base na comparação, preciso adicionar uma nova coluna no primeiro arquivo. A coluna C é a chave principal .

A,B,C,D
1,1990,I001,2473264
2,1991,I002,2473265
3,1992,I004,2473266
4,1993,6050,912432
5,1994,6003,912433

SEGUNDO ARQUIVO

A,B
I001,2.3 GHz
I002,2.3 GHz
I004,2.3 GHz
6050,1.8 GHz
6003,850 MHz

RESULTADO ESPERADO

A,B,C,D,E
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433

Este código está funcionando bem, mas se o registro não for correspondido, ele ignorará a linha do primeiro arquivo. Mas eu não quero que ele seja pulado e adicione 0 ou NA nessa coluna.

awk -F, 'NR==FNR{a[$1]=$2;next}a[$3]{print $0","a[$3]}' test2 test1
A,B,C,D
1,1990,I001,2473264
2,1991,I002,2473265
3,1992,I004,2473266
4,1993,6050,912432
5,1994,6003,912433
6,1995,6004,21234

Resultado esperado:

1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
    
por Akki 21.04.2018 / 03:30

3 respostas

0

Altere seu awk para

$ awk -F, 'NR==FNR{a[$1]=$2;next} FNR!=1{print $0","(a[$3]?a[$3]:"NA")}' SECOND FIRST
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,NA

Para obter seu primeiro resultado desejado:

$ awk -F, 'NR==FNR{a[$1]=$2;next} FNR!=1{$3=(a[$3]?a[$3]:"NA")","$3; print}' OFS=, SECOND FIRST
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433
6,1995,NA,6004,21234
    
por 21.04.2018 / 05:45
0

Seu programa awk está correto se nós o modificarmos para incondicionalmente usar

print $0","( a[$3] ? a[$3] : 0 )

em vez de usar

print $0","a[$3]

quando a[$3] é diferente de zero ou vazio. Ou seja, use um zero se o campo a[$3] for zero ou vazio, caso contrário, use a[$3] .

Em outras palavras,

awk -F, -v OFS=',' 'FNR==NR { a[$1]=$2; next } FNR > 1 { print $0, (a[$3] ? a[$3] : 0) }' fileB fileA

Usamos FNR > 1 aqui para pular o cabeçalho.

Usando join :

$ join -t , -1 3 -o 1.1,1.2,1.3,1.4,2.2 fileA fileB
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz

Se os arquivos não estão classificados na chave de junção, então (em um shell que suporta substituições de processos):

$ join -t , -1 3 -o 1.1,1.2,1.3,1.4,2.2 <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
4,1993,6050,912432,1.8 GHz
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz

O join executará uma operação INNER JOIN nos dois arquivos. O -t , informa join que as vírgulas são o delimitador de campo e escolhemos o terceiro campo como a chave de junção no primeiro arquivo com -1 3 (o primeiro campo no segundo arquivo é assumido como sendo a chave, a menos que -2 N para o mesmo outro campo N nesse arquivo).

O sinal -o informa a join quais campos gostaríamos de incluir na saída e de qual arquivo ( x.y significa coluna y do arquivo x ).

join é uma operação muito rápida, mas requer que os arquivos de entrada sejam classificados na chave de junção (tivemos sorte com o primeiro exemplo acima). A saída final no segundo exemplo acima é não-classificada em relação ao campo primeiro , mas você pode consertar isso facilmente colocando-o em sort -k1,1n .

Para o segundo cenário, com uma incompatibilidade,

$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -a 1 -e 0  <( sort -t, -k3,3 fileA ) <( sort fileB )
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0
4,1993,6050,912432,1.8 GHz
A,B,C,D,0
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz

Ao adicionar -a 1 -e 0 , pedimos que join sempre exiba todos os campos do primeiro arquivo (-a 1 ) e insira zeros para cada campo que estiver faltando no segundo arquivo.

Como você pode ver, agora obtemos o resultado correto, mas o cabeçalho do primeiro arquivo também está incluído (porque solicitamos). Se você quiser remover os cabeçalhos dos dados de ambos os arquivos (e classificar o resultado), então

$ join -t, -1 3 -o1.1,1.2,1.3,1.4,2.2 -e 0 -a1  <( tail -n +2 fileA | sort -t, -k3,3 ) <( tail -n +2 fileB | sort ) | sort -k1,1n
1,1990,I001,2473264,2.3 GHz
2,1991,I002,2473265,2.3 GHz
3,1992,I004,2473266,2.3 GHz
4,1993,6050,912432,1.8 GHz
5,1994,6003,912433,850 MHz
6,1995,6004,21234,0

Este comando funcionaria realmente para ambos os cenários.

    
por 21.04.2018 / 08:32
0

Usando GNU join com os dados estendidos e o primeiro formato de saída, mais echo e tail para substituir o cabeçalho, (porque join fica confuso com cabeçalhos inconsistentes):

echo A,B,C,D,E
join -t ',' --header --nocheck-order test1 test2 \
     -a 1 -e NA -1 3 -2 1 -o 1.1,1.2,2.2,1.3,1.4 | tail -n +2

Saída:

A,B,C,D,E
1,1990,2.3 GHz,I001,2473264
2,1991,2.3 GHz,I002,2473265
3,1992,2.3 GHz,I004,2473266
4,1993,1.8 GHz,6050,912432
5,1994,850 MHz,6003,912433
6,1995,NA,6004,21234
    
por 21.04.2018 / 08:55

Tags