
我有一個如下所示的文件:
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 列,而有些行只有一列。我想將單列行連接在一起,以便每個組合行上最多有 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)}
:嵌套三元 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,此時我們列印整個模式空間並返回讀取下一行。
- 現在我們知道下一行也是單一字段,因此我們繼續剪切連接模式空間中這兩個部分的換行符。
- 模式空間是否有 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
檢查 shebang #!/usr/bin/awk -f
,因為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