単一の列を持つ行を行の最大4つの列に結合するには?

単一の列を持つ行を行の最大4つの列に結合するには?

次のファイルがあります。

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

一部の行には2つ以上の列があり、他の行には1つの列しかないことは明らかです。結合された各行に最大4つの列があるように、単一の列行を結合したいと思います。したがって、出力は次のようになります。

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

実際のデータが大きいことを考慮してこれを行う方法に関する提案はありますか?

ベストアンサー1

少し寛容ですが、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 

説明する:
awk変数:
NF =フィールド数
FS =フィールドセパレータ=デフォルトスペーススペース
RS =レコードセパレータ=デフォルト改行。
c=カウンター

ライン1: {printf "%s",(NF==1?$0 FS:(c==0?"":RS) $0 RS)}:演算の場合、入れ子になった三項

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

これは疑似コードで説明できます。たとえば、次のようになります。

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   

2号線: {(NF==1?++c:c=0)}:別の三項if演算で次のように表現できます。

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

行3: c==4{printf "\n";c=0}クラシックawk構文:condition{action}

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

行4: END{printf "\n"}' file:スクリプトの最後に新しい行を印刷します。

おすすめ記事