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 awk
lo que mencioné. Primero solo para file_1
y file_2
para obtener output_1
, luego únete file_3
y file_4
para obtener output_2
. Después de eso, uso $ join output_1 output_2
para 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.30
un "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 -t
opciones 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.