
Me gustaría fusionar columnas específicas de dos archivos de texto que contienen un número variable de filas, pero el mismo número de columnas (como se muestra a continuación):
file1:
xyz desc1 12
uvw desc2 55
pqr desc3 12
file2:
xyz desc1 56
uvw desc2 88
Preferred output:
xyz desc1 12 56
uvw desc2 55 88
pqr desc3 12 0
Actualmente uso el comando pegar usando awk como:
paste <(awk '{print $1}' file1) <(awk '{print $2}' file1) <(awk '{print $3}' file1) <(awk '{print $3}' file2)
Pero esto parece fusionar sólo las columnas que se superponen. ¿Hay alguna manera en awk de insertar ceros en lugar de omitir la fila misma?
Necesito combinar 100 archivos de modo que mi archivo de salida contenga 102 columnas.
Respuesta1
Si el orden de las columnas es importante, es decir, los números del mismo archivo deben mantenerse en la misma columna, deberá agregar relleno mientras lee los diferentes archivos. Aquí hay una forma que funciona con GNU awk:
fusionar.awk
# Set k to be a shorthand for the key
{ k = $1 SUBSEP $2 }
# First element with this key, add zeros to align it with other rows
!(k in h) {
for(i=1; i<=ARGIND-1; i++)
h[k] = h[k] OFS 0
}
# Remember the data element
{ h[k] = h[k] OFS $3 }
# Before moving to the next file, ensure that all rows are aligned
ENDFILE {
for(k in h) {
if(split(h[k], a) < ARGIND)
h[k] = h[k] OFS 0
}
}
# Print out the collected data
END {
for(k in h) {
split(k, a, SUBSEP)
print a[1], a[2], h[k]
}
}
Aquí hay algunos archivos de prueba : f1
, y :f2
f3
f4
$ tail -n+1 f[1-4]
==> f1 <==
xyz desc1 21
uvw desc2 22
pqr desc3 23
==> f2 <==
xyz desc1 56
uvw desc2 57
==> f3 <==
xyz desc1 87
uvw desc2 88
==> f4 <==
xyz desc1 11
uvw desc2 12
pqr desc3 13
stw desc1 14
arg desc2 15
Prueba 1
awk -f merge.awk f[1-4] | column -t
Producción:
pqr desc3 23 0 0 13
uvw desc2 22 57 88 12
stw desc1 0 0 0 14
arg desc2 0 0 0 15
xyz desc1 21 56 87 11
Prueba 2
awk -f merge.awk f2 f3 f4 f1 | column -t
Producción:
pqr desc3 0 0 13 23
uvw desc2 57 88 12 22
stw desc1 0 0 14 0
arg desc2 0 0 15 0
xyz desc1 56 87 11 21
Editar:
Si la salida debe estar separada por tabulaciones, configure el separador de campo de salida en consecuencia:
awk -f merge.awk OFS='\t' f[1-4]
Respuesta2
Prueba esto:
$ awk '
FNR == NR { a[$1,$2] = $3; next }
{
print $0,(($1,$2) in a) ? a[$1,$2] : "0"
}
' file2 file1
xyz desc1 12 56
uvw desc2 55 88
pqr desc3 12 0
Respuesta3
Esto es un poco largo, pero funciona:
$ cat file1 file2 | awk '{a[$1FS$2]=a[$1FS$2]FS$3; b[$1FS$2]++} END {for (i in b) max=max<b[i]?b[i]:max; for (i in a) {printf "%s %s", i, a[i]; for (j=b[i]; j<max; j++) printf "%s0", FS printf "%s", RS}}'
pqr desc3 12 0
xyz desc1 12 56
uvw desc2 55 88
El bloque awk se puede formatear de la siguiente manera:
awk '{a[$1FS$2]=a[$1FS$2]FS$3; b[$1FS$2]++}
END {for (i in b) max=max<b[i]?b[i]:max
for (i in a) {printf "%s%s%s", i, FS, a[i]
for (j=b[i]; j<max; j++) printf "%s0", FS
printf "%s", RS}
}'
La idea es imprimir todos los archivos y luego capturar los valores repetidos en la matriz a[$1 $2]
. Además, b[$1 $2]
contiene la cantidad de veces que apareció un par ( $1
, ).$2
En el END{}
bloque seguimos recorriendo los valores y completando con tantos 0
s como faltan desde el número de elementos hasta el número máximo de elementos.