
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
sed
Um 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 awk
Speicherort 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