鉴于以下data
文件...
foo 10
bar 20
oof 50
rab 20
Run Code Online (Sandbox Code Playgroud)
...我如何将第二列打印为第二列总数的百分比?换句话说,我想要...
foo 10 10%
bar 20 20%
oof 50 50%
rab 20 20%
Run Code Online (Sandbox Code Playgroud)
...当然,数字不太明显。我可以很容易地创建一个运行总数,但我不确定如何在打印行之前计算总数。我在 awk 文件中执行此操作totals.awk
...
#!/usr/bin/awk -f
BEGIN{
runningtotal=0
}
{
runningtotal=runningtotal+$2
print $1 "\t" $2 "\t" runningtotal "\t" $2/runningtotal
}
Run Code Online (Sandbox Code Playgroud)
所以,运行./totals.awk data
收益...
foo 10 10 1
bar 20 30 0.666667
oof 50 80 0.625
rab 20 100 0.2
Run Code Online (Sandbox Code Playgroud)
有没有办法循环两次,一次计算总数,一次打印行?这在 AWK 中是可能的,还是我必须使用其他实用程序?
Joh*_*024 16
要通过一次调用来创建表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%
Run Code Online (Sandbox Code Playgroud)
该文件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
提供指数符号。如果某些数字特别大或特别小,这将很有用。
如果您要多次使用它,则键入长命令会很不方便。而是创建一个函数或脚本来插入命令。
要创建一个名为 的函数totals
,请运行以下命令:
$ totals() { awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"; }
Run Code Online (Sandbox Code Playgroud)
定义此函数后,data
可以通过运行以下命令找到所调用数据文件的百分比:
$ totals data
Run Code Online (Sandbox Code Playgroud)
要使定义totals
永久化,请将其放在您的~/.bashrc
文件中。
如果您更喜欢脚本,请创建一个totals.sh
包含以下内容的文件:
#!/bin/sh
awk 'FNR==NR{s+=$2;next;} {printf "%s\t%s\t%s%%\n",$1,$2,100*$2/s}' "$1" "$1"
Run Code Online (Sandbox Code Playgroud)
要获取名为 的数据文件的百分比data
,请运行:
sh totals.sh data
Run Code Online (Sandbox Code Playgroud)