将每 n 行相加

将每 n 行相加

我正在研究对多次运行命令给出的多个数据点进行平均。在这种特殊情况下,我使用的是sysbench工具套件。

此示例输入来自单次sysbench cpu <parameters>运行;请记住,这将运行多次,因为我希望对某些结果进行平均:

CPU speed:
    events per second:   827.81

General statistics:
    total time:                          30.0021s
    total number of events:              44977

Latency (ms):
         min:                                    2.01
         avg:                                    4.93
         max:                                  733.85
         95th percentile:                       12.98
         sum:                               228990.08

在我的示例脚本中

(for ((n=0;n<3;n++)); do
    <command> | grep -i <data point lines>;
done) | awk '{ print $(NF) }'

我从每次运行中获取相关数据点并打印(作为我将使用的任何代码的占位符)下面每行的最后一个字段。这包含我需要使用的数字。我需要的是将每 n 个 $(NF) 加在一起,然后对它们进行平均,我已经可以概念化了。

让我们从这个例子中说,我想采取这些观点(目前通过 grep 但不关心实现)

events per second:   827.81
avg:                                    4.93
max:                                  733.85
95th percentile:                       12.98

并从中获取最后一列(当前通过 awk '{ print $(NF) }')

827.81
4.93
733.85
12.98

假设每个周期和 n 个周期有 4 行输出,我想添加与同一字段匹配的所有行(因此所有 avg: 都被求和并平均,对于 max: 和其他统计数据也是如此。)

add lines 1/5/9/4n
          2/6/10/4n
          3/7/11/4n
          4/8/12/4n
together

我正在尝试使用 awk (因为此代码将在多个 unix 系统上使用,并且 awk 是一个常见因素),但如果我使这个过于复杂并且有更好的替代方案,我很高兴听到它。

答案1

你可以获得一些东西关闭到你想要的:

$ awk -F'[: ]' -v OFS=: '{sub("^ *","")};
    /^(events|avg|min|95th)/ { sum[$1] += $NF ; count[$1]++ };
    END { for (i in sum) print i, sum[i]/count[i] }' input.[123]
95th:11.3133
avg:4.53
events:691.143
min:2.31

注意:input.1、input.2 和 input.3 是示例输入的副本,并稍微编辑了值。

另请注意:sub()在脚本的第一行中使用以去除任何前导空格。由于 $0 已更改,因此会重新评估字段拆分,因此我们保证 $1 中有一个可用的(短)名称。我们并不真正关心它是什么,只关心它唯一标识我们从中提取值的记录类型。

不幸的是,因为它使用关联数组,所以输出的顺序是伪随机的(即您不能指望以任何特定顺序出现的元素)。为了获得一致的顺序,您可以使用sort第一个输出字段,然后cut仅获取值。

$ awk -F'[: ]' -v OFS=: '{sub("^ *","")};
    /^(events|avg|min|95th)/ { sum[$1] += $NF ; count[$1]++ };
    END { for (i in sum) print i, sum[i]/count[i] }' input.[123] |
  sort -t: -k1,1 | cut -d: -f2
11.3133
4.53
691.143
2.31

如果您有 GNU awk,则可以使用该asorti()函数对关联数组的索引进行排序,从而无需通过管道输入sortand cut

$ awk -F'[: ]' -v OFS=: '{sub("^ *","")};
    /^(events|avg|min|95th)/ {sum[$1] += $NF ; count[$1]++ };
    END {
      num=asorti(sum,idx);
      for (i=1;i<=num;i++) print sum[idx[i]]/count[idx[i]]
    }' input.[123]
11.3133
4.53
691.143
2.31

答案2

编写你的脚本如下:

{ for ((n=0; n<4; n++)); do <command>; done; } |\
awk -v t=$n 'i==t{ i=0 }
    /(events per second|avg|max|95th percentile):/{ seen[++i]+=$NF/t }
END{ for(x in seen) print x, seen[x] }'

相关内容