2

I wanna write a bash script to calculate the avg time of capture packets by the net interface. I find this answer that give me a hand, but I need to improve my script. So I extended it in this way

#!/bin/bash

INTERVAL="1"  # interval in seconds

if [ -z "$1" ]; then
        echo
        echo usage: $0 [network-interface]
        echo
        echo e.g. $0 "$1"
        echo
        echo shows packets-per-second
        exit
fi

N_PPS=0
SUM_TIME=0

calc_avg()
{
    AVG=$((N_PPS/SUM_TIME))
    echo
    echo "The average of packet captured is $AVG pkts/s"
    exit 0
}

trap calc_avg SIGINT

while true
do
        R1=`cat /sys/class/net/$1/statistics/rx_packets`
        sleep $INTERVAL
        R2=`cat /sys/class/net/$1/statistics/rx_packets`
        RXPPS=`expr $R2 - $R1`
    SUM_TIME=$((SUM_TIME + 1))
    if [ "$RXPPS" > 0 ];
    then
        N_PPS=$((N_PPS + RXPPS))
    fi
    echo "RX $1: $RXPPS pkts/s"
done

As I explain I need to have the AVG time of the packets captured, so i count my packet with N_PPS. I need to understand better if this calculation is correct, both for SUM_TIME and AVG_TIME, and how to have microseconds instead seconds, in bash.

Any advice or critic are well accepted.

EDIT AFTER CHANGES

  1. I did changes thanks to @jarr answer but I have the problem, if the result is less han 1, not showing the inizial 0. I.e. AVG = .333

    AVG=$(echo "scale=3; $N_PPS/$SUM_TIME" | bc )

  2. I notice that when I launch this script, it creates a file called 0 of 0 bytes. Why and how to avoid this ?

Community
  • 1
  • 1
Kyrol
  • 3,475
  • 7
  • 34
  • 46

1 Answers1

1

The code seems mathematically correct but of course it might be lacking accuracy for the data gathering variable $INTERVAL. Maybe it can be set as argument? But it depends on your needs. Here some quick optimization done.

Some points (based on my experience, maybe others can point to some unneeded changes).

I prefer printf to echo since it allows more control. Plus I read somewhere awhile ago that it is more portable.

You don't need expr to evaluate commands into variables.

I personally prefer usage to go into its own function for added readability. The function should return a success value given the fact that its calling is expected, it is not exactly an error.

Double parenthesis can be used for adding a variable to itself by one.

#!/bin/bash

INTERVAL="1"  # interval in seconds
N_PPS=0
SUM_TIME=0

trap calc_avg SIGINT

fn_usage()
{
    printf "\nusage: $0 [network-interface]\n"
    printf "\ne.g. $0 $1\n"
    printf "\nshows packets-per-second\n"
    exit 0
}

calc_avg()
{
    AVG=$((N_PPS/SUM_TIME))
    printf  "\nThe average of packet captured is $AVG pkts/s\n"
    exit 0
}


if [[ -z $1 ]]; then
    fn_usage
fi

while true; do
    R1=$( cat /sys/class/net/$1/statistics/rx_packets )
    sleep $INTERVAL
    R2=$( cat /sys/class/net/$1/statistics/rx_packets )
    RXPPS=$(( $R2 - $R1 ))
    ((SUM_TIME += 1))

    if [[ $RXPPS > 0 ]]; then
        ((N_PPS += RXPPS))
    fi
    printf "RX $1: $RXPPS pkts/s\n"
done
jarr
  • 102
  • 2
  • 7
  • I did EDIT. Please take a look. – Kyrol Jan 25 '16 at 14:54
  • 1
    Point 1, that's because bash does not handle natively decimal notation. So it rounds the numbers. Point 2, that's because of this [ "$RXPPS" > 0 ], it is recommended to use -gt following the link below or you can simply do double square brackets. http://unix.stackexchange.com/questions/169198/0-byte-file-created-in-a-simple-script – jarr Jan 25 '16 at 16:26
  • Yes, you're right for the `>`. Completely lost in my head! Any advice to solve 1) ? – Kyrol Jan 25 '16 at 20:31
  • Hello Kyrol, use this link. http://stackoverflow.com/questions/2331936/bash-scripting-and-bc Here they use the bc command to handle floating point. It is a bit awkward but gets the job done. Anyway, if you plan to make tools in the future I can recommend you to also learn Python, which is really good for these type of uses. – jarr Jan 26 '16 at 19:43
  • Thank you! Yes, maybe for this think is better to do a Python script. – Kyrol Jan 27 '16 at 09:47