如何在 bash 中计算 ASCII 文件数据的平均值?

如何在 bash 中计算 ASCII 文件数据的平均值?

在 bash 中,我可以从日志文件中 grep 一些时间测量值,如下所示

grep "time:" myLogfile.txt | cut -d' ' -f 3 >> timeMeasurements.txt

#timeMeasurements.txt
2.5
3.5
2.0
...

现在我想根据中的值计算平均值timeMeasurements.txt。在 bash 中执行此操作的最快方法是什么?
我知道有 gnuplot 和 R,但似乎必须为它们中的任何一个编写一些冗长的脚本。

答案1

必修GNU 数据聚合版本

$ datamash mean 1 < file
2.6666666666667

在旁边:感觉确实如此应该有可能天生地bc(即不使用 shell 或外部程序来循环输入值)。GNU实现bc包含一个read()函数 - 但是让它检测输入结束似乎非常困难。我能想到的最好的办法是:

#!/usr/bin/bc

scale = 6
while( (x = read()) ) {
  s += x
  c += 1
}
s/c
quit

然后你可以通过管道将文件输入到只要你用任何非数字字符终止输入例如

$ { cat file; echo '@'; } | ./mean.bc
2.666666

答案2

您可以使用awk。Bash 本身不太擅长数学......

awk 'BEGIN { lines=0; total=0 } { lines++; total+=$1 } END { print total/lines }' timeMeasurements.txt

笔记

  • lines=0; total=0将变量设置为 0
  • lines++每行增加lines
  • total+=$1将每行的值添加到累计总数中
  • print total/lines完成后,将总数除以值的数量

答案3

另一种方法是使用sedbc

sed 's/^/n+=1;x+=/;$ascale=1;x/n' timemeasurements.txt | bc

sed 表达式将输入转换为如下内容:

n+=1;x+=2.5
n+=1;x+=3.5
n+=1;x+=2.0
scale=1;x/n

它通过bc管道逐行进行评估。

答案4

您可以使用bc基本计算器,循环while如下read

count=0; sum=0; while read -r num; do ((count++)); sum=$(echo "$sum + $num" | bc); done < timeMeasurement.txt; echo "scale=2; $sum / $count" | bc -l

或者更易读的是:

count=0
sum=0
while read -r num
do
  ((count++))
  sum=$(echo "$sum + $num" | bc)
done < timeMeasurement.txt
echo "scale=2; $sum / $count" | bc -l

解释:

  • 首先,我们将值的数量和总和设置为变量 count 和 sum,值为 0。
  • 逐行读取文件,将行中的值设置为变量 num。我们使用构造while read -r num; do ... ; done < timeMeasurements.txt来执行此操作。这意味着我们将对文件的每一行执行某些操作。
  • 在 while 循环中,使用 bash 算术将每行计数变量增加一((count++))
  • $(...)使用带echo管道的bash 命令替换将bc文件此行的 num 变量的值添加到所有先前行的 num 变量的总和中。bc因为 bash 不能很好地处理浮点运算。

此时循环结束,count变量包含时间测量值的数量,sum变量包含时间测量的总和。

  • 与我们的变量一起使用echo来创建传递给的平均值计算bc。该scale=2部分告诉bc要显示多少个有效数字。

相关内容