用AWK计算并除以总数

Rip*_*eeb 7 awk arithmetic

鉴于以下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提供指数符号。如果某些数字特别大或特别小,这将很有用。

制作一个shell函数

如果您要多次使用它,则键入长命令会很不方便。而是创建一个函数或脚本来插入命令。

要创建一个名为 的函数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文件中。

编写一个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"
Run Code Online (Sandbox Code Playgroud)

要获取名为 的数据文件的百分比data,请运行:

sh totals.sh data
Run Code Online (Sandbox Code Playgroud)