Using sed commands on an output to find an average Using sed commands on an output to find an average unix unix

Using sed commands on an output to find an average


This can all be done with awk pretty easily. Assuming your ping output looks like this:

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

This will do the trick:

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}'

We use the NR variable to check which line of output is being processed and then increment the appropriate variable. (The value is gotten by splitting the time field on the equals sign.)


You don't have to make it that complicated. Do something like

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

Sample Output

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


A pure Bash solution is not possible, because Bash has no support for floating point arithmetic. You need at least bc.

In order to calculate an average it is not necessary to collect and store all values. You can calculate the average incrementally. See here or here for the mathematics or read Volume 2 of Donald Knuth's "The Art of Computer Programming". The formula as a Bash function might look like this:

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"}

A single ping time can be collected by the following function.

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

With the above functions the calculation of n average values with m samples for each average can be done with two for loops.

n=3m=10for 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' $adone

In the outer loop the average a is first cleared. In the inner loop the ping time is measured. If the average is empty it is initialized with the first sample. Otherwise the average is calculated. And the result is reported in the outer loop.

bc and printf behave differently depending on the localization. If necessary a specific behavior can be forced by setting LC_NUMERIC.

If you wish you can add a sleep 1 in front of the ping, to measure only one sample per second.