¿Cómo unir filas con columnas individuales hasta un máximo de 4 columnas en una fila?

¿Cómo unir filas con columnas individuales hasta un máximo de 4 columnas en una fila?

Tengo un archivo que se parece a continuación:

1 
4 5 6 7 19
20
22
24 26 27 
29
30
31
32 
34 
40 
50 
56 
58
100
234 235 270 500
1234 1235 1236 1237
2300
2303
2304
2307
2309

Como queda claro, hay algunas filas con más de 1 columna y otras con una sola columna. Me gustaría unir filas de una sola columna de modo que haya como máximo 4 columnas en cada fila combinada. Entonces la salida debería verse así:

1  
4 5 6 7 19
20 22
24 26 27 
29 30 31 32
34 40 50 56 
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309

¿Alguna sugerencia sobre cómo hacer esto, considerando que los datos reales son grandes?

Respuesta1

Un poco idiomático pero trabajando con gnu awk:

awk '{printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)} \
{(NF==1?++c:c=0)} \
c==4{printf "\n";c=0} \
END{printf "\n"}' file

#Output
1 
4 5 6 7 19
20 22 
24 26 27
29 30 31 32 
34 40 50 56 
58 100 
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307 
2309 

Explicación:
variables awk:
NF=Número de campos
FS=Separador de campos = espacio por defecto
RS=Separador de registros= nueva línea por defecto.
c=contador

Línea 1: {printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)}: ternario anidado si operaciones

#Single ternary if operation:
condition?true action:false action
#Nested if operations:  
condition1?true action 1:(condition2:true action2:false action2) #nested ternary if operations   
-------------------------[            ^ false action1 ^        ]   

Esto se puede explicar en pseudocódigo como:

if NF==1 then print $0 and print FS   
else (if c==0 then print "" else print RS) and print $0 and print RS again   

Línea 2: {(NF==1?++c:c=0)}: Otra operación if ternaria que se puede expresar como:

If NF==1 (line has one field) 
then increase counter c by one 
else reset counter c.  

Línea 3 : c==4{printf "\n";c=0}Sintaxis clásica de awk:condition{action}

If counter c==4 then print a new line and reset counter c

Línea 4: END{printf "\n"}' file: Esto simplemente imprime una nueva línea al final del script.

Respuesta2

Puedes utilizar sedpara obtener lo que deseas:

sed -e '
   /./!b
   /[^[:space:]]/!b
   /[^[:space:]][[:blank:]]\{1,\}[^[:space:]]/b

   :loop
      $q;N
      /\n.*\S[[:blank:]]\+\S/b
      s/\n/ /;tdummy
      :dummy
      s/[[:space:]]\{1,\}/&/3;t
   bloop
' yourfile


Explicaciones

  • Omita líneas vacías, en blanco y con NF > 1.
  • Configure un bucle do- while en el punto donde el espacio del patrón contiene una línea de campo único.
  • Tomamos la siguiente línea y verificamos si tiene NF > 1, momento en el cual imprimimos todo el espacio del patrón y volvemos a leer la siguiente línea.
  • Ahora sabemos que la siguiente línea también es de un solo campo, así que continuamos y recortamos la nueva línea que une estas dos partes en el espacio del patrón.
  • ¿El espacio del patrón ya tiene 3 espacios? En caso afirmativo, imprimimos todo el espacio del patrón y comenzamos a leer la siguiente línea.
  • De lo contrario, volvemos al bucle que a su vez leerá la siguiente línea pero la adjuntará al espacio del patrón existente.

Resultado

1
4 5 6 7 19
20 22
24 26 27
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307
2309

Respuesta3

Uso: ./join_rows.awk input.txt

Verifique Shebang #!/usr/bin/awk -f, porque la awkubicación puede diferir en su sistema.

#!/usr/bin/awk -f

BEGIN {
    count = 1;
}

{
    if (NF == 1) {
        if (count > 1 && count <= 4) printf " ";

        printf "%s", $1;
        count++;

        if (count > 4) {
            printf "\n";
            count = 1;
        }
    } else {
        if (count > 1) printf "\n";

        print;
        count = 1;
    }
}

END {
    if(count > 1) printf "\n";
}

Producción:

1
4 5 6 7 19
20 22 
24 26 27  
29 30 31 32
34 40 50 56
58 100
234 235 270 500
1234 1235 1236 1237 
2300 2303 2304 2307
2309

Respuesta4

Extendidopapar moscasacercarse:

reorganizar_columnas.awkguion:

#!/bin/awk -f
function printRow(a, i, v)
{
    for (i in a) {
        printf "%s ", a[i]
    }
   print ""
   delete a
}
NF <= 2{
    for (i=1; i<=NF; i++) { 
        a[++c] = $i 
        if (length(a) == 4) {
            c = 0 
            printRow(a) 
        }
    }
}
NF > 2{
    if (length(a) > 0) {
        c = 0
        printRow(a)
    }
    print $0 
}
END{ print }

Uso:

awk -f rearrange_columns.awk yourfile

La salida:

1 
4 5 6 7 19
20 22 
24 26 27 
29 30 31 32 
34 40 50 56 
58 100 
234 235 270 500
1234 1235 1236 1237
2300 2303 2304 2307 
2309

información relacionada