
以下のようなファイルがあります:
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 列以上ある行もあれば、1 列しかない行もあります。結合された各行に最大 4 列が含まれるように、1 列の行を結合したいと思います。出力は次のようになります。
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)}
: ネストされた三項if演算
#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
: これはスクリプトの最後に新しい行を印刷するだけです。
答え2
sed
必要なものを取得するには、以下を使用できます。
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
説明
- 空行、空白行、および NF > 1 の行をスキップします。
- パターン スペースが単一フィールド行を保持するポイントで do-while ループを設定します。
- 次の行を取得して、NF > 1 であるかどうかを確認します。その時点で、パターン スペース全体を出力し、次の行の読み取りに戻ります。
- 次の行も単一フィールドであることがわかったので、パターン スペースでこれらの 2 つの部分を結合する改行を切り取ります。
- パターン スペースにはまだ 3 つのスペース チャンクがありますか? はいの場合は、パターン スペース全体を印刷し、次の行の読み取りを開始します。
- それ以外の場合は、ループに戻って次の行を読み取りますが、それを既存のパターン スペースに添付します。
結果
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
答え3
使用法: ./join_rows.awk input.txt
場所はシステムによって異なる可能性がある#!/usr/bin/awk -f
ため、shebang を確認してください。awk
#!/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";
}
出力:
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
答え4
拡張驚いて見るアプローチ:
列を並べ替える.awk脚本:
#!/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 }
使用法:
awk -f rearrange_columns.awk yourfile
出力:
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