我想从文件中提取数据并将其组织在一个大的固定宽度表中。我预计该表将有多个列,假设有 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
的正则表达式。FS
a
- 将
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