Sopalajo de Arrierez
Sopalajo de Arrierez

Reputation: 3860

Ping on shell scripts: Some packet loss, but error code $? equals to zero. How can I detect?

Sometimes my DSL router fails in this strange manner:

luis@balanceador:~$ sudo ping 8.8.8.8 -I eth9
[sudo] password for luis:
PING 8.8.8.8 (8.8.8.8) from 192.168.3.100 eth9: 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=47 time=69.3 ms
ping: sendmsg: Operation not permitted
64 bytes from 8.8.8.8: icmp_seq=3 ttl=47 time=68.0 ms
ping: sendmsg: Operation not permitted
64 bytes from 8.8.8.8: icmp_seq=5 ttl=47 time=68.9 ms
64 bytes from 8.8.8.8: icmp_seq=6 ttl=47 time=67.2 ms
ping: sendmsg: Operation not permitted
64 bytes from 8.8.8.8: icmp_seq=8 ttl=47 time=67.2 ms
^C
--- 8.8.8.8 ping statistics ---
8 packets transmitted, 5 received, 37% packet loss, time 7012ms
rtt min/avg/max/mdev = 67.254/68.183/69.391/0.906 ms
luis@balanceador:~$ echo $?
0

As can be seen, error code $? is 0. So I can not simply detect if the command failed, as the output yields no error for any script.

What is the proper way to detect that there were some packet loss?
Do I need to parse the output with grep or there is some simpler method?

Upvotes: 5

Views: 2323

Answers (1)

pmod
pmod

Reputation: 10997

According to the man page, by default (on Linux), if ping does not receive any reply packets at all, it will exit with code 1. But if a packet count (-c) and deadline timeout (-w, seconds) are both specified, and fewer packets before timeout are received, it will also exit with code 1. On other errors it exits with code 2.

ping 8.8.8.8 -I eth9 -c 3 -w 3

So, the error code will be set if 3 packets are not received within 3 seconds.

As @mklement0 noted, ping on BSD behaves in a bit different way:

The ping utility exits with one of the following values:

0 - at least one response was heard from the specified host.

2 - the transmission was successful but no responses were received.

So, in this case one should try workaround it with sending one by one in a loop

ip=8.8.8.8
count=3
for i in $(seq ${count}); do
   ping ${ip} -I eth9 -c 1
   if [ $? -eq 2 ]; then
      ## break and retransmit exit code
      exit 2
   fi
done

Of course, if you need full statistics, just count codes "2" and "0" to some variables and print result / set error code after for loop if you need.

Upvotes: 4

Related Questions