Unindo várias colunas de arquivos diferentes usando awk

Unindo várias colunas de arquivos diferentes usando awk

Eu tenho 4 arquivos tsv (separados por tabulação) que se parecem com isto:

arquivo_1:

abc 1
def 2
ghi 3

arquivo_2:

abc 2
ghi 3

arquivo_3:

def 1
ghi 2
jkl 4

arquivo_4:

ghi 3
jkl 4

Quero juntar esses arquivos para obter 1 arquivo tsv como este:

dataset file_1 file_2 file_3 file_4
abc     1      2             
def     2      4            
ghi     3      3      2      3
jkl                   4      4

Eu tentei usarawk

$ awk '
    BEGIN{OFS=FS="\t"} 
    FNR==1{f = f "\t" FILENAME} 
    NR==FNR{a[$1] = $2} 
    NR!=FNR{a[$1] = a[$1] "\t" $2} 
    END{printf "dataset%s\n", f; for(i in a) print i, a[i]}
  ' file_{1..4}

Este comando funciona, mas mudei o valor. Digamos que se a primeira e a segunda colunas tiverem valor vazio e a terceira e quarta colunas tiverem valores 4 e 4, a saída que obtive desse comando é que a primeira e a segunda colunas têm valor 4, mas a terceira e a quarta colunas têm valor vazio. Então, tento juntar meu arquivo tsv separadamente usando awko que mencionei. Primeiro apenas para file_1e file_2para obter output_1, depois junte file_3e file_4para obter output_2. Depois disso, uso $ join output_1 output_2para mesclar output_1 e output_2, mas só obtenho valores que existem em 4 arquivos. Perdi dados que existem apenas em um arquivo.

Eu apreciarei muito se você puder me dar um conselho.

Obrigado

Responder1

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ datasets[$1]; fnames[FILENAME]; vals[$1,FILENAME] = $2 }
END {
    printf "%s", "dataset"
    for (fname in fnames) {
        printf "%s%s", OFS, fname
    }
    print ""
    for (dataset in datasets) {
        printf "%s", dataset
        for (fname in fnames) {
            printf "%s%s", OFS, vals[dataset,fname]
        }
        print ""
    }
}

$ tail -n +1 file?
==> file1 <==
a       1
b       2
c       3

==> file2 <==
a       2
c       3

$ awk -f tst.awk file1 file2
dataset file1   file2
a       1       2
b       2
c       3       3

Adicione quantos arquivos desejar à lista.

Responder2

Com join (GNU coreutils) 8.30e "substituição de processo", você pode tentar

join -a1 -a2 -t"    " -oauto  -e " " <(join -a1 -a2 -t" " -oauto  -e "" file[12]) <(join -a1 -a2 -t"    " -oauto  -e " " file[34])
abc 1   2        
def 2       1    
ghi 3   3   2   3
jkl         4   4

As -topções possuem um <TAB>valor de caractere.

Responder3

Conselho por enquanto: codifique para mais tarde, se precisar.

Eu manteria três arrays enquanto você lê todos os arquivos.

(a) Para cada novo arquivo, uma lista hash de nomes de arquivos.
(b) Para cada novo conjunto de dados, uma lista hash de $1.
(c) Para cada linha, uma lista hash de valores

FNR == 1 { ++htFile[FILENAME]; }
! ($1 in htSet) { ++htSet[$1]; }
{ htVal [FILENAME, $1] = $2; }

Em uma função End, itere sobre htFile e htSet.

function Table (r, c, buf) {
    buf = "dataset";
    for (c in htFile)
        buf = sprint ("%s\t%s", buf, htFile[c]);
    print buf;
    for (r in htSet) {
        buf = "";
        for (c in htFile)
            buf = sprint ("%s\t%s", buf, htVal[c, r]);
        print substr (buf, 2);
    }
}
END { Table( ); }

Isso não mantém a ordem dos arquivos e conjuntos de dados na tabela de saída. Se isso for importante, você pode manter uma versão sequenciada das tabelas e iterar na ordem original.

informação relacionada