Junção Externa Esquerda / Direita vs. Junção Externa Completa
O problema com o comando que você está usando é que requer que todas as entradas no arquivo2 estejam no arquivo1. A seção de impressão da instrução está avaliando apenas as entradas que estão no arquivo2.
FNR
e NR
são frequentemente usados dessa maneira para JOIN com base em uma semelhança - escolhendo todos os registros de um conjunto de dados e apenas os registros relacionados do outro conjunto de dados. O que você implementou é especificamente um 'RIGHT OUTER JOIN', já que ele irá inserir todas as entradas do lado 'direito' - file2 e membros correspondentes do lado esquerdo, file1.
Em vez disso, você deseja conduzir um 'FULL OUTER JOIN'. Todos os registros em ambos os arquivos com uma mesclagem de registros com base na coluna 1.
FNR==NR
significa que o número de registros 'FILE' ( FNR
) é igual ao número total de registros ( NR
). NR
será incrementado para cada linha de qualquer arquivo processado, enquanto FNR
será redefinido para 0 ao iniciar um novo arquivo. Portanto, FNR==NR
só é verdadeiro ao importar 2+ arquivos durante a leitura no primeiro arquivo. Quando o awk muda para o próximo arquivo, o FNR irá resetar para 0, enquanto o NR continuará a crescer.
Para ilustrar isso, inseri uma instrução print para fornecer o estado dessas variáveis conforme o awk processa a entrada:
$> awk 'FNR==NR{a[$1]=$2;printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]); next} {printf("File: %s, NR: %s, FNR: %s, $1: %s, $2: %s, a[$1]$2: %s\n",FILENAME,NR,FNR,$1,$2,a[$1]$2); }' file1 file2
File: file1, NR: 1, FNR: 1, $1: 001, $2: A, a[$1]: A
File: file1, NR: 2, FNR: 2, $1: 002, $2: B, a[$1]: B
File: file1, NR: 3, FNR: 3, $1: 003, $2: C, a[$1]: C
File: file1, NR: 4, FNR: 4, $1: 004, $2: D, a[$1]: D
File: file2, NR: 5, FNR: 1, $1: 002, $2: D, a[$1]$2: BD
File: file2, NR: 6, FNR: 2, $1: 003, $2: D, a[$1]$2: CD
File: file2, NR: 7, FNR: 3, $1: 005, $2: E, a[$1]$2: E
File: file2, NR: 8, FNR: 4, $1: 006, $2: F, a[$1]$2: F
Solução
Para corrigi-lo, tudo o que você precisa fazer é continuar adicionando entradas ao array enquanto processa o arquivo2, e somente envia os resultados após processar todos os arquivos de entrada.
Portanto, nesse caso, não nos importamos com NR
ou FNR
.
-
Para cada linha de texto de todos os arquivos de entrada, use seu valor de coluna um
$1
como um índice em uma matriza[$1]
-
Atribua o valor da coluna 2,
$2
, à matriz nesse índice, mas acrescente o valor para não sobrescrever um valor que já exista:a[$1]=a[$1]$2
-
Aguarde até que todos os registros / linhas tenham sido processados antes de imprimir o array:
for (i in a) { printf("%s\t%s\n", i, a[i]) }
A única desvantagem é que o awk usa matrizes associativas que usam índices baseados em strings, não integer (é por isso que isso funciona), mas um efeito colateral disso é que a ordem das entradas na matriz pode não ser como pretendido; neste caso, a impressão do conteúdo não está em ordem numérica (por índice), de modo que a saída da pipeta para classificar é necessária:
$> awk '{ a[$1]=a[$1]$2; next } END { for (i in a) { printf("%s\t%s\n", i, a[i]) } }' file1 file2 | sort -n
001 A
002 BD
003 CD
004 D
005 E
006 F
Abordagem alternativa
Você também pode usar o comando join para fazer isso, mas eu não sei como combiná-los - eles permanecem delimitados por espaço, então um estágio adicional de processamento é necessário:
$> join -o 0,1.2,2.2 -a1 -a2 file1 file2 | awk '{printf("%s\t%s%s\n", $1, $2, $3)}'
001 A
002 BD
003 CD
004 D
005 E
006 F
TODO
Isso não faz nada para rejeitar entradas duplicadas - que podem ou não ser desejadas. Atualmente, se você tiver registros duplicados em arquivos de entrada separados, eles serão combinados:
file1: 001 A
e file2: 001 A
resultará em um registro de saída de 001 AA