鉴于以下data
文件...
foo 10
bar 20
oof 50
rab 20
...我如何将第二列打印为第二列总数的百分比?换句话说,我想要...
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
...当然还有不太明显的数字。我可以很容易地创建一个运行总计,但我不知道如何才能在打印行之前计算总数。我正在 awk 文件中执行此操作totals.awk
...
#!/usr/bin/awk -f
BEGIN{
runningtotal=0
}
{
runningtotal=runningtotal+$2
print $1 "\t" $2 "\t" runningtotal "\t" $2/runningtotal
}
所以,运行./totals.awk data
收益...
foo 10 10 1
bar 20 30 0.666667
oof 50 80 0.625
rab 20 100 0.2
有没有办法循环两次,一次计算总数,一次打印行?这在 AWK 中可行吗?或者我必须使用其他实用程序?
答案1
要通过一次调用来创建表awk
:
$ awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' data data
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
怎么运行的
该文件data
作为参数提供给awk
两次。因此,它将被读取两次,第一次获取总计(存储在变量 中)s
,第二次打印输出。更详细地查看命令:
FNR==NR{s+=$2;next;}
NR 是已读取的记录(行)总数
awk
,FNR 是迄今为止从当前文件读取的记录数。因此,当 时FNR==NR
,我们正在读取第一个文件。发生这种情况时,变量s
会增加第二列中的值。然后,next
告诉awk
跳过其余命令并从下一条记录开始。请注意,不必初始化
s
为零。在 中awk
,所有数值变量默认都初始化为零。printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s
如果我们到达此命令,那么我们正在处理第二个文件。这意味着
s
现在保存了第 2 列的总计。因此,我们打印第 1 列、第 2 列和百分比100*$2/s
。
输出格式选项
使用printf
,可以对输出格式进行详细控制。上面的命令使用%s
适用于字符串、整数和浮点数的格式说明符。这里可能有用的其他三个选项是:
%d
将数字格式化为整数。如果数字实际上是浮点数,它将被截断为整数%f
将数字格式化为浮点数。还可以指定宽度和小数位,例如%5.2f
。%e
提供指数表示法。如果某些数字特别大或特别小,这将很有用。
制作一个shell函数
如果您要多次使用此命令,那么输入长命令会很不方便。相反,创建一个函数或脚本来执行该命令。
要创建名为 的函数totals
,请运行以下命令:
$ totals() { awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"; }
data
定义此函数后,可以通过运行以下命令找到调用的数据文件的百分比:
$ totals data
要使定义totals
永久,请将其放入您的~/.bashrc
文件中。
制作一个 shell 脚本
如果您更喜欢脚本,请创建一个名为的文件,totals.sh
其内容为:
#!/bin/sh
awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"
要获取名为 的数据文件的百分比data
,请运行:
sh totals.sh data
答案2
执行此操作的“简单”方法是调用awk
两次:一次获取总数,另一次计算比率。
$ total=$(awk 'BEGIN{ total=0 } { total=total+$2 } END{ printf total }' data)
$ awk -v total=$total '{ print $1 "\t" $2 "\t" 100*$2/total "%" }' data
现在我确信有人会以某种方式想出一句俏皮话......
答案3
awk 方式打开一个文件(为了完整性)
awk '{a[NR]=$0;x+=(b[NR]=$2)}END{while(++i<=NR)print a[i]"\t"100*b[i]/x"%"}' file
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
这将比其他方法使用更多内存,但速度应该更快
这会将行读入 arraya
并将字段二读入 array b
。
然后x
按字段 2 中的值递增。
最后,它从 1 迭代到记录数并输出正确的行并计算百分比。