Unir varias columnas de un archivo diferente usando awk

Unir varias columnas de un archivo diferente usando awk

Tengo 4 archivos tsv (separados por tabulaciones) que se ven así:

archivo_1:

abc 1
def 2
ghi 3

archivo_2:

abc 2
ghi 3

archivo_3:

def 1
ghi 2
jkl 4

archivo_4:

ghi 3
jkl 4

Quiero unirme a esos archivos para obtener 1 archivo 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

He intentado 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, pero obtuve un valor cambiado. Digamos que si la primera y la segunda columna tienen un valor vacío y la tercera y cuarta columna tienen el valor 4 y 4, el resultado que obtuve de ese comando es que la primera y la segunda columna tienen el valor 4, pero la tercera y la cuarta columna tienen un valor vacío. Entonces trato de unir mi archivo tsv por separado usando awklo que mencioné. Primero solo para file_1y file_2para obtener output_1, luego únete file_3y file_4para obtener output_2. Después de eso, uso $ join output_1 output_2para fusionar salida_1 y salida_2, pero solo obtengo el valor que existe en 4 archivos. Perdí datos que solo existen en un archivo.

Te agradeceré mucho si puedes darme un consejo.

Gracias

Respuesta1

$ 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

Agregue tantos archivos a la lista como desee.

Respuesta2

Con join (GNU coreutils) 8.30un "proceso de sustitución", puede intentar

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

Las -topciones tienen un <TAB>valor de carácter.

Respuesta3

Consejo por ahora: codifique para más adelante si lo necesita.

Mantendría tres matrices mientras lees todos los archivos.

(a) Para cada archivo nuevo, una lista hash de nombres de archivos.
(b) Para cada nuevo conjunto de datos, una lista hash de $1.
(c) Para cada fila, una lista hash de valores

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

En una función Finalizar, itere sobre htFile y 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( ); }

Esto no mantiene el orden de los archivos y conjuntos de datos en la tabla de salida. Si eso es importante, puede mantener una versión secuenciada de las tablas e iterar en el orden original.

información relacionada