当我尝试查找一列值的平均值时,我想获得确切的数字。
例如,这是输入值的列:
1426044
1425486
1439480
1423677
1383676
1360088
1390745
1435123
1422970
1394461
1325896
1251248
1206005
1217057
1168298
1153022
1199310
1250162
1247917
1206836
当我使用以下命令时:
... | awk '{ sum+=$1} END { print sum/NR}'
我得到以下输出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}'
为什么NR必须初始化为1呢?当我删除时NR == 1
,我得到错误的结果。
编辑2
我发现以下 awk 脚本有没有办法在单个命令中获取数字列表的最小值、最大值、中位数和平均值?。它将一次性获得单列数值数据的总和、计数、平均值、中值、最大值和最小值。它从标准输入读取,并在一行上打印输出的制表符分隔列。我稍微调整了一下。我注意到它不需要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]}
}
'
答案1
... | awk '{ sum+=$1} END { print sum/NR}'
默认情况下,(GNU) awk 打印最多 6 位有效数字(加上指数部分)的数字。这来自于默认值变量OFMT
。文档中没有这么说,但这仅适用于非整数值的数字。
您可以进行更改OFMT
以影响所有print
语句,或者更确切地说,仅printf
在此处使用,因此如果平均值恰好是整数,它也可以工作。类似于%.3f
打印小数点后三位数字的数字。
...| awk '{ sum+=$1} END { printf "%.3f\n", sum/NR }'
f
请参阅文档了解和的含义g
以及精度修饰符(.prec
在第二个链接中):
- https://www.gnu.org/software/gawk/manual/html_node/Control-Letters.html
- https://www.gnu.org/software/gawk/manual/html_node/Format-Modifiers.html
awk 'NR == 1 { max=$1; min=$1; sum=0 } ...'
这不会初始化NR
。相反,它检查是否NR
等于一,即我们在第一行。 (==
是比较,=
是赋值。) 如果是,则初始化max
、min
和sum
。没有它,max
就会min
从零开始。您永远不可能有负的最大值或正的最小值。
答案2
如果使用 GNU awk
,请尝试此操作。使用修饰符添加逗号'
。
$ awk '{sum+=$1}END{printf "%'\''.2f\n",sum/NR}' filename
1,316,375.05
$
如果你有的话jq
,试试这个。
$ jq -s min,max,add/length filename
1153022
1439480
1316375.05
$
单引号或撇号字符是 ISO C 的 POSIX 扩展。它表示浮点值的整数部分或整数十进制值的整个部分应包含千位分隔符。这只适用于支持此类字符的区域设置。例如: