Mesclar e imprimir valores correspondentes e não correspondentes entre um arquivo menor e um arquivo enorme

2

Eu tenho um arquivo delimitado por espaço relativamente pequeno que se parece com isso (mas com muitas colunas e linhas):

arquivo1:

Entry1
a
b
c
d

E outro arquivo delimitado por uma tabulação enorme com muitas entradas duplicadas por linha como esta:

arquivo2:

value       ID1   ID2   
1      a    aaaa1
1      a    aaaa2
1      b    bbbb1
1      b    bbbb2
1      b    bbbb3
1      d    aaaa4

Estou tentando imprimir primeiro um arquivo delimitado por tabulação do mesmo tamanho que o arquivo1, especificando correspondências entre cada entrada no campo file1 e ID1 (coluna 2) no arquivo2, como esta é uma questão separada :

Entry1
a
b
NoMatch
d

E também imprima um arquivo delimitado por tabulação mesclada com os valores de file1 e file2, desta vez com entradas repetidas se existirem no arquivo2, mas mantendo o NoMatch assim, assim:

value       ID1   ID2   
1      a    aaaa1
1      a    aaaa2
1      b    bbbb1
1      b    bbbb2
1      b    bbbb3
NoMatch NoMatch NoMatch
1      d    aaaa4

Eu tentei usar o comando join para me dar uma mensagem NoMatch:

join -a1 -e "NoMatch" <(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) <(cat file2 | sort -k1,1) > out.txt

mas devo estar fazendo algo errado, porque isso imprime todos os arquivos1, por exemplo, mas se não houver correspondência no arquivo2, os outros campos ficarão em branco (então nenhuma mensagem "NoMatch" aparece), por favor me ajude a entender O que estou fazendo errado?

Muito obrigado!

#

Obrigado gilles, parece que não respondi ao seu comentário, pois acabei de me inscrever ... O que você sugeriu:

join -a1 -e "NoMatch" -11 -22 --header -o2.1,2.2,2.3 file1 file2

resolveu a segunda consulta Output2, obrigado! Posso perguntar como posso obter o primeiro Output1, com as mesmas linhas do arquivo1? Obrigado novamente !!

Com a ajuda de don_crissti, posso obter o segundo resultado assim:

paste -d'\t' file2 <(awk 'FNR==NR{seen[$1]++; next}  {(FNR==1 || ($1 in seen)) || $1="NoMatch"};1'  file2  file1)
    
por user145913 03.12.2015 / 22:11

1 resposta

2

Reformate o exemplo original para facilitar a leitura:

join -a1 -e "NoMatch" \
 <(awk -F ' ' '{print $0}' file1.txt |tail -n +2|sort -k1,1) \
 <(cat file2 | sort -k1,1)

Todos os problemas estão com o processamento do arquivo2 e com as opções join .

  1. o arquivo2 é classificado no campo 1, deve ser o campo 2.
  2. Nenhuma opção -t '<tab>' para join , o arquivo2 é delimitado por tabulações.
  3. Ausente da opção join para ingressar no campo 2 do arquivo2.
  4. Mesmo com o campo join correto para o arquivo2, a saída padrão imprime o campo de união primeiro, portanto, é necessário especificar a opção -o FORMAT em join .
  5. o cabeçalho do arquivo2 não é removido.
  6. Não causando problemas, mas processamento desnecessário: tail é desnecessário no arquivo1 porque awk pode pular a primeira linha.
  7. Opção -F ' ' desnecessária para awk .

Corrigir esses problemas gera isso:

#!/bin/bash
head -1 file2
join -t '   ' -2 2 -a 1 -e NoMatch -o 2.1,2.2,2.3 \
 <(awk 'NR==1{next} {print $0}' file1.txt | sort) \
 <(tail -n +2 file2 | sort -k2)

Que produz a seguinte saída delimitada por tabulação:

value   ID1     ID2
1       a       aaaa1
1       a       aaaa2
1       b       bbbb1
1       b       bbbb2
1       b       bbbb3
NoMatch NoMatch NoMatch
1       d       aaaa4
    
por 04.12.2015 / 03:34