在输出上使用sed命令来查找平均值

时间:2017-04-27 05:07:41

标签: bash unix awk sed

我的目标是计算网站在前10个计数上的平均ping时间,计算第二个10个计数的平均值,并计算最后10个计数的平均值,并使用bash脚本一次打印它们。 到目前为止,我已经提出了以下脚本:

  ping -c 30 google.com > pings.txt 
  sed 's/\=/= /g' pings.txt > formatted_op.txt
  sed -n '2, 11p' formatted_op.txt > 1.txt
  sed -n '12, 22p' formatted_op.txt > 2.txt
  sed -n '22, 32p' formatted_op.txt > 3.txt

 awk '{print $10}' 1.txt | awk '{ sum += $1 } END {print sum/10}' > 1_avg.txt
 awk '{print $10}' 2.txt | awk '{ sum += $1 } END {print sum/10}' > 2_avg.txt
 awk '{print $10}' 3.txt | awk '{ sum += $1 } END {print sum/10}' > 3_avg.txt
 cat 1_avg.txt 2_avg.txt 3_avg.txt > final_avg.txt
 cat final_avg.txt
 rm 1.txt 2.txt 3.txt 1_avg.txt 2_avg.txt 3_avg.txt formatted_op.txt pings.txt

但是,我希望能够在不创建任何临时文件的情况下执行此操作。我该怎么办? 我也尝试使用管道进行如下操作:

  ping -c 30 google.com | sed 's/\=/= /g' | sed -n '2, 11p' | awk '{print $10}'| awk '{ sum += $1 } END {print sum/10}'

但这只计算前10次ping的平均值,使用ping 3次会产生不同的结果。

4 个答案:

答案 0 :(得分:2)

这一切都可以通过awk轻松完成。假设您的ping输出如下所示:

64 bytes from yyz08s09-in-f110.1e100.net (172.217.1.110): icmp_seq=27 ttl=59 time=0.636 ms
64 bytes from yyz08s09-in-f110.1e100.net (172.217.1.110): icmp_seq=28 ttl=59 time=0.638 ms
64 bytes from yyz08s09-in-f110.1e100.net (172.217.1.110): icmp_seq=29 ttl=59 time=0.658 ms
64 bytes from yyz08s09-in-f110.1e100.net (172.217.1.110): icmp_seq=30 ttl=59 time=0.666 ms

这样可以解决问题:

ping -c 30 google.com | \
awk '
{
    split($8,a,"=");
    if(NR > 1 && NR < 12) {
        round1+=a[2]
    } else if (NR < 22) {
        round2+=a[2]
    } else if (NR < 32) {
        round3+=a[2]
    }
}
END {
    print round1/10" "round2/10" "round3/10
}
'

我们使用NR变量来检查正在处理的输出行,然后递增适当的变量。 (通过在等号上分割时间字段来获取该值。)

答案 1 :(得分:1)

你不必那么复杂。做点什么

for i in {1..10}
do
 ping -c 30 google.com | tail -n1 | 
 awk -v count="$i" -v FS="/" '{print "Count", count,"average : ",$5}'
done

示例输出

Count 1 average :  78.484
Count 2 average :  74.473
Count 3 average :  76.971
Count 4 average :  78.789
Count 5 average :  103.609
Count 6 average :  105.754
Count 7 average :  98.969
Count 8 average :  99.009
Count 9 average :  86.186
Count 10 average :  86.521

答案 2 :(得分:1)

纯Bash解决方案是不可能的,因为Bash不支持浮点运算。您至少需要bc

为了计算平均值,不必收集和存储所有值。您可以逐步计算平均值。有关数学的信息,请参阅herehere或阅读Donald Knuth&#34; The Art of Computer Programming&#34;的第2卷。作为Bash函数的公式可能如下所示:

avg ()
{
  local a=$1 # average of the values already seen in the past
  local x=$2 # new sample
  local n=$3 # sequence number

  bc -l <<<"$a + ($x - $a) / $n"
}

以下功能可以收集单个ping时间。

pingtime ()
{
  ping -c1 ${host:-localhost} |
  sed -n 's/.*time=\(.*\) .*/\1/p'
}

使用上述函数,可以使用两个n循环计算每个平均值m样本的for平均值。

n=3
m=10

for i in $(seq $n); do
  a=
  for j in $(seq $m); do
    t=$(pingtime)
    if [ -z "$a" ]; then
      a=$t
    else
      a=$(avg $a $t $j)
    fi
  done
  LC_NUMERIC=C printf '%2g\n' $a
done

在外循环中,首先清除平均a。在内循环中,测量ping时间。如果平均值为空,则使用第一个样本初始化。否则计算平均值。结果在外循环中报告。

bcprintf的行为取决于本地化。如有必要,可以通过设置LC_NUMERIC来强制执行特定行为。

如果您希望在sleep 1前添加ping,则每秒只能测量一个样本。

答案 3 :(得分:0)

您也可以尝试我的解决方案

#!/bin/bash

pings=10

for i in {1..10};
do

  ping -c ${pings} google.pl | grep -o 'time=.*' | sed 's/time=\(.*\) ms/\1/g' | awk -v iteration="$i" -v pings="$pings" '{sum+=$1+$2+$3} END {print "Iteration " iteration " Average time " sum/pings}'

done