Sunday, 1 November 2009

Shell Script that shows Network Speed

The following shell script shows current download and upload speeds for the network interface you choose.

Copy the shell script in a file named, i.e: net_speed.sh

Then after setting execution permissions:
$ chmod a+x net_speed.sh

You can run the shell script passing as the first argument the network interface you want to monitor:
$ ./net_speed.sh eth0


You will get a line like that:
ppp0 DOWN:15 KB/s UP:880 B/s

This script works parsing /proc/net/dev file and calculating the difference between current transmitted or received bytes and their values one second ago.

#!/bin/bash

# This shell script shows the network speed, both received and transmitted.

# Usage: net_speed.sh interface
#   e.g: net_speed.sh eth0


# Global variables
interface=$1
received_bytes=""
old_received_bytes=""
transmitted_bytes=""
old_transmitted_bytes=""


# This function parses /proc/net/dev file searching for a line containing $interface data.
# Within that line, the first and ninth numbers after ':' are respectively the received and transmited bytes.
function get_bytes
{
line=$(cat /proc/net/dev | grep $interface | cut -d ':' -f 2 | awk '{print "received_bytes="$1, "transmitted_bytes="$9}')
eval $line
}


# Function which calculates the speed using actual and old byte number.
# Speed is shown in KByte per second when greater or equal than 1 KByte per second.
# This function should be called each second.
function get_velocity
{
value=$1    
old_value=$2

let vel=$value-$old_value
let velKB=$vel/1000
if [ $velKB != 0 ];
then
echo -n "$velKB KB/s";
else
echo -n "$vel B/s";
fi
}

# Gets initial values.
get_bytes
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

# Shows a message and waits for one second.
echo "Starting...";
sleep 1;
echo "";


# Main loop. It will repeat forever.
while true; 
do

# Get new transmitted and received byte number values.
get_bytes

# Calculates speeds.
vel_recv=$(get_velocity $received_bytes $old_received_bytes)
vel_trans=$(get_velocity $transmitted_bytes $old_transmitted_bytes)

# Shows results in the console.
echo -en "$interface DOWN:$vel_recv\tUP:$vel_trans\r"

# Update old values to perform new calculations.
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

# Waits one second.
sleep 1;

done


An improved version of this script


This version:

- displays speed using MegaBytes per second too

- displays data in a fixed way, using printf function.

- shows an error message if network interface not provided in command line.

- clears previous written line before writing another one.


Customize this line in the script to suit your display:
printf "%6s DOWN:%10s\tUP:%10s\r" "$interface" "$vel_recv" "$vel_trans"

Magic numbers 6, 10, and 10 are the fixed sizes of interface name, download and upload rates.

#!/bin/bash

# This shell script shows the network speed, both received and transmitted.

# Usage: net_speed.sh interface
#   e.g: net_speed.sh eth0


# Global variables
interface=$1
received_bytes=""
old_received_bytes=""
transmitted_bytes=""
old_transmitted_bytes=""


# This function parses /proc/net/dev file searching for a line containing $interface data.
# Within that line, the first and ninth numbers after ':' are respectively the received and transmited bytes.
function get_bytes
{
line=$(cat /proc/net/dev | grep $interface | cut -d ':' -f 2 | awk '{print "received_bytes="$1, "transmitted_bytes="$9}')
eval $line
}


# Function which calculates the speed using actual and old byte number.
# Speed is shown in KByte per second when greater or equal than 1 KByte per second.
# This function should be called each second.
function get_velocity
{
value=$1    
old_value=$2

let vel=$value-$old_value
let velKB=$vel/1000
let velMB=$vel/1000000
if [ $velMB != 0 ];
then
echo -n "$velMB MB/s";
elif [ $velKB != 0 ];
then
echo -n "$velKB KB/s";
else
echo -n "$vel B/s";
fi
}

#error and quit if no interface specified
if (( $# != 1 )); then
 echo "Illegal number of parameters."
 echo "Usage: $0 network_interface"
 exit 1
fi

# Gets initial values.
get_bytes
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

# Shows a message and waits for one second.
echo "Starting...";
sleep 1;
echo "";


# Main loop. It will repeat forever.
while true; 
do

# Get new transmitted and received byte number values.
get_bytes

# Calculates speeds.
vel_recv=$(get_velocity $received_bytes $old_received_bytes)
vel_trans=$(get_velocity $transmitted_bytes $old_transmitted_bytes)

#clear current line (\033[2K), move cursor back to start (\r)
echo -en "\033[2K\r"

# Shows results in the console.
#echo -en "$interface DOWN:$vel_recv\tUP:$vel_trans\r"
printf "%6s DOWN:%10s\tUP:%10s\r" "$interface" "$vel_recv" "$vel_trans"

# Update old values to perform new calculations.
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

# Waits one second.
sleep 1;

done

19 comentarios:

Moemen Mostafa said...

Thanks very much for this script. I used it on a cisco telepresence server to monitor the actual bandwidth usage.

Vicente Hernando said...

Hi Moemen Mostafa,

happy to read it was useful to you!

Sam said...

Your code has a bug. You should not divide by 1000 in get_velocity, you should divide by 1024 (the number of bytes in a kilobyte).

Vicente Hernando said...

Hello Sam,

in storage capacity and data rate transmission, International System of Units (SI) are usually used. So k means 1000 instead of 1024 for speed.
Binary prefix (Wikipedia)"

Anyway, thank you for pointing that!

Jim said...

How do U handle descending byte counts?
What I perceived was Previous - Current. Thus if byte count drops there is a negative number?

Vicente Hernando said...

Hello Jim,

does it make physical sense a descending byte count? (There are separated transmitter and a receiver counters)

I think not, so I did not take into account that case.

Gabi said...

Hi,

This is a great script, would you consider adding Mb display on it?

Thanks !

Vicente Hernando said...

Hi Gabi,

in order to show MB/s you should change this piece of code:

let vel=$value-$old_value
let velKB=$vel/1000
if [ $velKB != 0 ];
then
echo -n "$velKB KB/s";
else
echo -n "$vel B/s";
fi
}

into this one:

let vel=$value-$old_value
let velKB=$vel/1000
let velMB=$vel/1000000
if [ $velMB != 0 ];
then
echo -n "$velMB MB/s";
elif [ $velKB != 0 ];
then
echo -n "$velKB KB/s";
else
echo -n "$vel B/s";
fi
}

Cheers,
Vicente.

Gabi said...

Thank you Vicente,looks really nice now, just one more thing I noticed after running it for a while, when it switches from KB to B you can see a lot of /sss. I tried to add a clear in the loop but it makes it impossible to stop.

Gabi

Vicente Hernando said...

Hi Gabi,

as a workaround you could add spaces before \t and \r

echo -en "$interface DOWN:$vel_recv  \tUP:$vel_trans  \r"

Tune that line adding spaces and \t as you need.

Gabi said...

Thank you, I will test that also, I' using the output on a 20x4 display so I can't use too many spaces.

Vicente Hernando said...

I have not tested it, but if you already know your display size,you could also echo 20 spaces then \r then write the right speed.

Vicente Hernando said...

The better way should be using printf function:

Instead of
echo -en "$interface DOWN:$vel_recv\tUP:$vel_trans\r"

something like:
printf "%s DOWN:%6d\t%6d\r" $interface $vel_trans $vel_recv

Change the 6 into the size of the number it suits you.

Cheers,
Vicente.

Vicente Hernando said...

I have tested it and it has a problem. I will update the script well when I am not busy.

Gabi said...

Thank you for this, there is no rush, whenever you have time it's ok.

Vicente Hernando said...

Hi Gabi,

in the end I added another script with the features you wanted.

Cheers,
Vicente.

Gabi said...

Hi Vicente,

This one is perfect.
Thank you very much !

CGar said...

Tweaked script. Added error if you happen to forget the interface. If you forget the script still tries to run and makes a mess. Changed the division to 1024 and 1048576 for MegaBytes. Also added code to clear the line before refreshing. Since if a key is accidently pressed, any output will remain in the spaces of the main output.

========

#!/bin/bash

# This shell script shows the network speed, both received and transmitted.

# Usage: net_speed.sh interface
# e.g: net_speed.sh eth0

# Global variables
interface=$1
received_bytes=""
old_received_bytes=""
transmitted_bytes=""
old_transmitted_bytes=""

# This function parses /proc/net/dev file searching for a line containing $interface data.
# Within that line, the first and ninth numbers after ':' are respectively the received and transmited bytes.
function get_bytes
{
line=$(cat /proc/net/dev | grep $interface | cut -d ':' -f 2 | awk '{print "received_bytes="$1, "transmitted_bytes="$9}')
eval $line
}

# Function which calculates the speed using actual and old byte number.
# Speed is shown in KByte per second when greater or equal than 1 KByte per second.
# This function should be called each second.
function get_velocity
{
value=$1
old_value=$2

let vel=$value-$old_value
let velKB=$vel/1024
let velMB=$vel/1048576 #1024 ^ 2 (equal to dividing by 1024 twice)
if [ $velMB != 0 ];
then
echo -n "$velMB MB/s";
elif [ $velKB != 0 ];
then
echo -n "$velKB KB/s";
else
echo -n "$vel B/s";
fi
}

#error and quit if no interface specified
if (( $# != 1 )); then
echo "Illegal number of parameters"
echo "Usage: netspeed.sh "
exit 1
fi

# Gets initial values.
get_bytes
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

echo "====================="
echo "Network Speed Monitor"
echo "====================="
echo ""

# Main loop. It will repeat forever.
while true;
do
# Get new transmitted and received byte number values.
get_bytes

# Calculates speeds.
vel_recv=$(get_velocity $received_bytes $old_received_bytes)
vel_trans=$(get_velocity $transmitted_bytes $old_transmitted_bytes)

#clear current line (\033[2K), move cursor back to start (\r) and show results in the console with tabs for spacing
echo -en "\033[2K\rInterface: $interface\tDownload: $vel_recv\tUpload: $vel_trans"

#Alternatively you can use printf
#printf "%6s DOWN:%10s\tUP:%10s\r" "$interface" "$vel_recv" "$vel_trans"

# Update old values to perform new calculations.
old_received_bytes=$received_bytes
old_transmitted_bytes=$transmitted_bytes

# Waits one second.
sleep 1;
done

Vicente Hernando said...

Hi CGar,

thank you very much for your tweaked script!

I have updated the post with your points.

However I rather left 1000 and 1000000 for K and M to calculate speed.


Cheers,
Vicente.