在 awk 中调用数组来创建具有固定宽度列的表

在 awk 中调用数组来创建具有固定宽度列的表

我想从文件中提取数据并将其组织在一个大的固定宽度表中。我预计该表将有多个列,假设有 30 列。如果我使用传统awk命令行创建此表,那么我将需要编写一个非常长的awk命令行,类似于以下内容:

awk '{printf "%-5s  %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s %-5s\n", $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30}'

有没有办法让这个线性更短?例如,我正在考虑在前面的长命令中实现一个数组。该数组将告诉awk我想要创建的列的数量和宽度,而不是单独定义每一列,如下所示:

awk 'BEGIN {for i in {1..30}; do echo %-5s\n print i}

如何在内部正确实现该方法awk以创建多个固定宽度的列?

答案1

您可以在循环内进行打印本身,一次一个字段。

awk '{for(i=1;i<=NF;i++) { printf "%-5s",$i } ; printf("\n"); }'

请注意,循环后需要打印换行符,以防止多行合并为一行。

例如

echo a b c 32 87 x5 | awk '{for(i=1;i<=NF;i++) { printf "%-5s",$i } ; printf("\n"); }'
a    b    c    32   87   x5  

答案2

您可以(但我不建议这样做)分步骤构建一些变量(bash 中的示例):

$ printf -v l '%s ' {1..30}           # list of numbers to use
$ printf -v a '%.0s%%-5s ' $l         # make a string of repeated "%-5s"
$ printf -v b ',$%s' $l               # make string of field numbers as "$1,$2.."
$ awk -va="$a" '{printf a "\n"'"$b"'}' infile4

但你也可以在 awk 中完成这一切:

$ awk '{split($0,a); for(i in a){printf "%-5s", $i}; print ""}' infile
  • in将使用与用于将行拆分为字段并将每个值放入数组中split相同awk的正则表达式。FSa
  • for(自动)循环遍历所有字段。
  • 将以printf相同的格式打印所有字段。
  • 并且,最后print将在行尾放置一个换行符。

这更加灵活,因为它适用于任意数量的字段,甚至是具有不同数量字段的行。并且仅用一种语言就可以完成(更易于理解和维护)。

甚至:

$ awk 'for(i=1;i<=NF;i++){ printf("%-5s",$i) }; print ""}' infile

您可以将格式更改为%-5.5s剪切长度超过 5 个字符的字段。

请注意,awk 的 printf 错误地将分解的字符计数为两个字符。它似乎计算 Unicode 代码点(一个常见问题)而不是 Unicode 簇。


编辑 从评论中回答这个附加问题:

对表中定义第 27 列的行求和

只需添加所需的代码:

$ awk '{split($0,a); 
        sum=sum+a[27];
        for(i in a){ printf "%-5s", $i };
        print ""
       } END {
       print "Sum of column 27 is =", sum }
      ' infile

相关内容