UNIX pega columnas e inserta ceros para todos los valores faltantes

UNIX pega columnas e inserta ceros para todos los valores faltantes

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 :f2f3f4

$ 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 0s como faltan desde el número de elementos hasta el número máximo de elementos.

información relacionada