testing ping response

Hi!

I'm trying to create a script for seeing if a host is alive, and depending on the ammount of packet loss, send an mail+sms to warn if the host seems to be dead.

The script i'm trying to use is:

pinger ()
{
ping_stat=`ping -c 4 host.name | grep loss | awk '{print $7}'`
echo "Packet loss reported = $ping_stat"
test_
}

test_ ()
{
if [[ $ping_stat < 25% ]]
        then
                if [[ $ping_count < 2 ]]
                        then
                                let ping_count=ping_count+1
                                echo "More than 25% packet loss! I will take a nap for 2 minutes and then try again before I determine wether or not the host is down!"
                                sleep 120
                                echo "Trying again! Ping_count is $ping_count."
                                pinger
                        else
                                echo "The host host.name does not respond to ping or is heavily loaded with traffic. Packet loss is $ping_stat. Please investigate ASAP!"

                fi
        else
                echo "Host is responding well!"
fi

}
for _switch ; do
        case $_switch in
        -remote)
                ping_count=1
                pinger 
                ;;
        -boot)
                sleep 90
                get_ip=`ifconfig em0 | grep inet | awk '{print $2'}`
                get_hostname=`uname -n`
                message="$get_hostname has just (re)booted. (new) IP is $get_ip"
                sms=`echo $message | sed 's/ /+/g'`
#              code for sending sms goes here!
                echo $message > /tmp/ip_mail.txt
                mail -s "$get_hostname" mail@he.re < /tmp/ip_mail.txt
                rm /tmp/ip_mail.txt
                ;;
        esac

No matter if packet loss reported is 0 or 100%, the script reports the host as dead.

Any suggestions what I am doing wrong?

  1. Strip off the percent sign. The shell can't calculate with this - it doesn't know what % is in terms of arithmetics, ie. write a plain 25.
    So in the line

add something like

  | sed 's/%//g'
  

To strip off the percent symbol there too.
2. When doing arithmetics, I would use (( and )) instread of [[ and ]].

Thank you zaxxon!

May I ask you, why (( )) instead of [[ ]] ?
I'm still learning, so i don't know the difference yet. =)

(()) is for arithmetics, to treat numbers as numbers and not as text
[[]] is for testing against test options or strings etc.

See the man page for your shell for details. (( )) is used for arithmetic evaluation so is more suited to calculations and numeric comparisons. [[ ]] is used for conditional expressions, which includes some numeric stuff but is also useful for matching strings, testing for the presence of files, directories, and other types of devices, etc. If you were to use [[ ]] the syntax would be:

if [[ $ping_stat -lt 25 ]]

-lt being short for "less than".

Thanks for your help, it means a lot to me in my learning.
Now I'm stuck again, and i don't know how to solve this problem. =(

I want to put the hostname as a agument when running the script. Like:
script.sh -remote host.name

In this case, the hostname would be $2, but, when i do

ping_stat=`ping -c 4 $2 | grep loss | awk '{print $7}' | sed 's/%//g'`

it fails.
It seems that using $2 inside the variable doesn't work...
Can anyone please explain to me why it doesn't work, and how to get what i want to work?
I've been trying for some hours now, but I can't find any sollution, nor an answer to why it doesn't work. =(

if you use "((" then you have to use "test" keyword to test something
"[" is a test command in unix so
if (( test $a -gt "10" )) == if [ $a -gt "10 ]

ping_stat=`ping -c 4 $2 | grep loss | awk '{print $7}' |cut -d % -f1`
ping will take $2 there is no problem i guess please paste what error you are getting??

vidyadhar85:
Hmm... so, in my case, you suggest i should use something like

if (( test $ping_stat -gt "25" ))

?

Just for now though, it seems like

if (( $ping stat < 25 ))

works like i want it to do...

Whats the difference between the two given examples?

Lets begin with the full source:

#! /usr/local/bin/bash

pinger ()
{
ping_stat=`ping -c 4 host.name | grep loss | awk '{print $7}' | sed 's/%//g'`
echo "Packet loss reported = $ping_stat"
test_
}

test_ ()
{
if (( $ping_stat > 25 ))
        then
                if (( $ping_count < 2 ))
                        then
                                let ping_count=ping_count+1
                                echo "More than 25% packet loss! I will take a nap in 2 minutes and then try again before i determine if host is down!"
                                sleep 120
                                echo "Trying again! Ping_count is $ping_count."
                                pinger
                        else
                                echo "The host $2 does not respond to ping. Please investigate ASAP!"
                                touch /tmp/no.notify.beacon
                                looper
                fi
        else
                echo "Host is responding!"
fi

}

looper ()
{
ping_stat_loop=`ping -c 4 host.name | grep loss | awk '{print $7}' | sed 's/%//g'`
echo "Packet loss reported = $ping_stat"
if (( $ping_stat_loop > 75 ))
        then
                echo "Host still down. Trying again in 60 seconds..."
                sleep 60
                looper
        else
                echo "0% packet loss! Host is alive!"
                rm -rf /tmp/no.notify.beacon
fi
}

for _switch ; do
        case $_switch in
        -remote)
                if [ -e /tmp/no.notify ]
                        then
                                exit 0
                        else
                                ping_count=1
                                pinger ;;
                fi
        -boot)
                sleep 90
                get_ip=`ifconfig em0 | grep inet | awk '{print $2'}`
                get_hostname=`uname -n`
                message="$get_hostname has just (re)booted. (new) IP is $get_ip"
                sms=`echo $message | sed 's/ /+/g'`
                echo $message > /tmp/ip_mail.txt
                mail -s "$get_hostname" mail@he.re < /tmp/ip_mail.txt
                rm -rf /tmp/ip_mail.txt
                echo $sms
                ;;
        esac
done

exit 0

And, if i change host.name to $2, this is what i get...

./pingtest.sh -remote host.name

usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]
            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]
            [-P policy] [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]
            [-W waittime] [-z tos] host
       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]
            [-M mask | time] [-m ttl] [-P policy] [-p pattern] [-S src_addr]
            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]
            [-z tos] mcast-group
Packet loss reported =
./pingtest.sh: line 12: ((: > 25 : syntax error: operand expected (error token is "> 25 ")
Host is responding!

i mean to say "(("=test="[" these three are equal you can use any of these with if..
and try to run your script sh -x ./scriptname -remote host.name you will get an idea where exactly you are going wrong :slight_smile:

Hmm.. i did that, and still I have no clue why using host as argument doesn't work...
Here the output:

sh -x pingtest.sh -remote host.name 
+ [ -e /tmp/no.notify ]
+ ping_count=1
+ pinger
+ ping -c 4
usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]
            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]
            [-P policy] [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]
            [-W waittime] [-z tos] host
       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]
            [-M mask | time] [-m ttl] [-P policy] [-p pattern] [-S src_addr]
            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]
            [-z tos] mcast-group
+ grep loss
+ awk {print $7}
+ sed s/%//g
+ ping_stat=
+ echo Packet loss reported =
Packet loss reported =
+ test_
+
+ 1
1: not found
+ echo The host  does not respond to ping. Please investigate ASAP!
The host  does not respond to ping. Please investigate ASAP!
+ touch /tmp/no.notify.beacon
+ looper
+ ping -c 4
usage: ping [-AaDdfnoQqRrv] [-c count] [-G sweepmaxsize] [-g sweepminsize]
            [-h sweepincrsize] [-i wait] [-l preload] [-M mask | time] [-m ttl]
            [-P policy] [-p pattern] [-S src_addr] [-s packetsize] [-t timeout]
            [-W waittime] [-z tos] host
       ping [-AaDdfLnoQqRrv] [-c count] [-I iface] [-i wait] [-l preload]
            [-M mask | time] [-m ttl] [-P policy] [-p pattern] [-S src_addr]
            [-s packetsize] [-T ttl] [-t timeout] [-W waittime]
            [-z tos] mcast-group
+ grep loss
+ awk {print $7}
+ sed s/%//g
+ ping_stat_loop=
+ echo Packet loss reported =
Packet loss reported =
+
+ echo Host still down. Trying again in 60 seconds...
Host still down. Trying again in 60 seconds...
+ sleep 60

I stopped the script with ctrl+c, since it would otherwise get stuck in an infinite loop.

Damn, this is really getting annoying...
Just to test it, inside the case, in the -remote part, i added:
echo $2
exit 0
before setting the ping_count..
And guess what, it echoed the hostname as it should.. so why doesn't $2 work in the rest of the code? *argh*

In the remote section of the case, try calling pinger as

pinger $2 ;;

and then in pinger,

 
ping_stat=`ping -c 4 $1 | grep loss | awk '{print $7}' | sed 's/%//g'`

oh man got your problem...
in your script ping is inside the pinger() function right are you passing any arguments to it?? no right??
so where ever you call pinger type pinger $2
hope it works...

I think me and vi-curious both gave the answere at the same time:)

heh, i guess you did.

Thanks a lot guys, that worked just like a charm! =)

Uhm... just.. one more thing.. =(
I get the same problem after the 120 second sleep...
I change that to

                                sleep 120
                                echo "Trying again! Ping_count is $ping_count."
                                pinger $2

So now i'm back to square one.. =(
It take the $2 argument the first time, but not the second.. and I don't have a clue why..
And I'd guess, since this doesn't work, I guess that looper $2 won't work either... =(

I get the same information with sh -x as last time..
Any suggestions?

simple!!!
when you pass the argument to script first time
include var=$2 imean store $2 in some variable
then pass $var as a argument to pinger after sleep
it should work :slight_smile:

Ofcource...
I think I was a bit to tired yesterday, and i got to bed before you answered.
You were right, that was all i needed to do.

Thanks a lot! =)