如何将具有单列的行连接到一行中最多 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

很明显,有些行有超过 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

相关内容