Wie verbindet man Zeilen mit einzelnen Spalten zu maximal 4 Spalten in einer Zeile?

Wie verbindet man Zeilen mit einzelnen Spalten zu maximal 4 Spalten in einer Zeile?

Ich habe eine Datei, die wie folgt aussieht:

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

Wie man sieht, gibt es einige Zeilen mit mehr als einer Spalte und andere mit nur einer einzigen Spalte. Ich möchte einspaltige Zeilen so zusammenfügen, dass jede kombinierte Zeile höchstens vier Spalten enthält. Die Ausgabe sollte also folgendermaßen aussehen:

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

Gibt es irgendwelche Vorschläge, wie dies zu bewerkstelligen ist, wenn man bedenkt, dass die tatsächlichen Daten sehr umfangreich sind?

Antwort1

Ein bisschen idiomatisch, aber funktioniert mit 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 

Erläuterung:
awk-Variablen:
NF=Anzahl der Felder
FS=Feldtrennzeichen = standardmäßig Leerzeichen
RS=Datensatztrennzeichen = standardmäßig neue Zeile.
c=Zähler

Linie 1: {printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)}: verschachtelte ternäre if-Operationen

#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 ^        ]   

Dies kann in Pseudocode wie folgt erklärt werden:

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   

Zeile 2: {(NF==1?++c:c=0)}: Eine weitere ternäre if-Operation, die wie folgt ausgedrückt werden kann:

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

Zeile 3: c==4{printf "\n";c=0}Klassische Awk-Syntax:condition{action}

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

Zeile 4: END{printf "\n"}' file: Dies druckt einfach eine neue Zeile am Ende des Skripts.

Antwort2

sedUm das gewünschte zu erhalten, können Sie Folgendes verwenden :

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


Erläuterungen

  • Überspringen Sie leere Zeilen, Leerzeilen und Zeilen mit NF > 1.
  • Richten Sie eine Do-While-Schleife an der Stelle ein, an der der Musterbereich eine Zeile mit einem einzelnen Feld enthält.
  • Wir greifen uns die nächste Zeile zu und prüfen, ob sie NF > 1 hat. An diesem Punkt drucken wir den gesamten Musterbereich aus und fahren mit dem Lesen der nächsten Zeile fort.
  • Jetzt wissen wir, dass die nächste Zeile auch ein Einzelfeld ist, also fahren wir fort und schneiden die neue Zeile ab, die diese beiden Teile im Musterbereich verbindet.
  • Verfügt der Musterraum bereits über 3 Leerzeichenblöcke? Wenn ja, drucken wir den gesamten Musterraum und beginnen mit dem Lesen der nächsten Zeile.
  • Andernfalls verzweigen wir zurück zur Schleife, die wiederum die nächste Zeile liest, sie aber an den vorhandenen Musterbereich anfügt.

Ergebnis

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

Antwort3

Verwendung: ./join_rows.awk input.txt

Überprüfen Sie Shebang #!/usr/bin/awk -f, da der awkSpeicherort auf Ihrem System abweichen kann.

#!/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";
}

Ausgabe:

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

Antwort4

ErweitertgaffenAnsatz:

Spalten neu anordnen.awkSkript:

#!/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 }

Verwendung:

awk -f rearrange_columns.awk yourfile

Die Ausgabe:

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

verwandte Informationen