awk 的数字格式和舍入问题

rpl*_*lee 4 command-line awk numeric-data mawk text-formatting

当我试图找到一列值的平均值时,我想得到确切的数字。

例如,这是输入值列:

1426044
1425486
1439480
1423677
1383676
1360088
1390745
1435123
1422970
1394461
1325896
1251248
1206005
1217057
1168298
1153022
1199310
1250162
1247917
1206836
Run Code Online (Sandbox Code Playgroud)

当我使用以下命令时:

... | awk '{ sum+=$1} END { print sum/NR}'
Run Code Online (Sandbox Code Playgroud)

我得到以下的输出:1.31638e+06。但是,我想要1316375.05这种格式的确切数字,甚至更好 1,316,375.05

如何仅使用命令行工具执行此操作?

编辑 1

我发现了以下单行 awk 命令,它将为我提供最大值、最小值和平均值:

awk 'NR == 1 { max=$1; min=$1; sum=0 } { if ($1>max) max=$1; if ($1<min) min=$1; sum+=$1;} END {printf "Min: %d\tMax: %d\tAverage: %.2f\n", min, max, sum/NR}'
Run Code Online (Sandbox Code Playgroud)

为什么NR必须初始化为1?当我删除时NR == 1,我得到了错误的结果。

编辑 2

我从有没有办法在单个命令中获取数字列表的最小值、最大值、中值和平均值中找到以下 awk 脚本. 它将一次性获得单列数字数据的总和、计数、平均值、中值、最大值和最小值。它从 stdin 读取,并在一行上打印输出的制表符分隔列。我稍微调整了一下。我注意到它不需要NR == 1与上面的 awk 命令不同(在我的第一次编辑中)。有人可以解释为什么吗?我认为这与数字数据已排序并放入数组有关。

#!/bin/sh

sort -n | awk '

  $1 ~ /^(\-)?[0-9]*(\.[0-9]*)?$/ {
    a[c++] = $1;
    sum += $1;
  }
  END {
    ave = sum / c;
    if( (c % 2) == 1 ) {
      median = a[ int(c/2) ];
    } else {
      median = ( a[c/2] + a[c/2-1] ) / 2;
    }

    {printf "Sum: %d\tCount: %d\tAverage: %.2f\tMedian: %d\tMin: %d\tMax: %d\n", sum, c, ave, median, a[0], a[c-1]}
  }
'
Run Code Online (Sandbox Code Playgroud)

ilk*_*chu 7

... | awk '{ sum+=$1} END { print sum/NR}'
Run Code Online (Sandbox Code Playgroud)

默认情况下,(GNU) awk 打印最多 6 位有效数字(加上指数部分)的数字。这是来自默认值OFMT变量。它在文档中没有说,但这仅适用于非整数值。

您可以更改OFMT以影响所有print语句,或者更确切地说,仅printf在此处使用,因此如果平均值恰好是整数,它也可以使用。类似的东西%.3f会在小数点后打印三位数字。

...| awk '{ sum+=$1} END { printf "%.3f\n", sum/NR }'
Run Code Online (Sandbox Code Playgroud)

有关fandg和精度修饰符的含义,请参阅文档(.prec在第二个链接中):

awk 'NR == 1 { max=$1; min=$1; sum=0 } ...'
Run Code Online (Sandbox Code Playgroud)

这不会初始化NR。相反,它检查是否NR等于 1,即我们在第一行。(==是比较,=是赋值。)如果是,则初始化max,minsum。没有那个,max并且min将从零开始。您永远不会有负的最大值或正的最小值。


ste*_*eve 6

如果使用 GNU awk,试试这个。通过使用'修饰符添加逗号。

$ awk '{sum+=$1}END{printf "%'\''.2f\n",sum/NR}' filename
1,316,375.05
$
Run Code Online (Sandbox Code Playgroud)

如果你有jq,试试这个。

$ jq -s min,max,add/length filename
1153022
1439480
1316375.05
$
Run Code Online (Sandbox Code Playgroud)

来自gnu.org:gawk 格式修饰符

单引号或撇号字符是 ISO C 的 POSIX 扩展。它表示浮点值的整数部分或整数十进制值的整个部分应包含千位分隔符。这仅适用于支持此类字符的语言环境。例如: