LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Looping with until and grep: (https://www.linuxquestions.org/questions/programming-9/looping-with-until-and-grep-4175423069/)

ali2011 08-20-2012 09:44 AM

Looping with until and grep:
 
I am confused about the reason why the following script is reaching the "red" printf for some IPs in the file. This happens although the string "packet loss" that grep looks for ALWAYS exists in with all IPS! In otherwords, ALL hosts should stop from the first until loop (i.e., TRIES = 2).


Code:

#!/bin/sh

INDEX=1;
while read loop; do
TRIES=2;
printf '[%d]\tIP = %-15s\t[%d]\n' $INDEX $loop `expr $TRIES - 1`;
        until sudo ping -i 0.025 -c 2 $loop > $loop.loss && grep -q "packet loss" $loop.loss; do
                if [ "$TRIES" -ge 3 ]; then
                        printf '[%d]\tIP = %-15s\t[-]\n' $INDEX $loop;
                        break;
                        echo "";
                fi;
                printf '[%d]\tIP = %-15s\t[%d]\n' $INDEX $loop $TRIES;
                TRIES=`expr $TRIES + 1`;
        done;
INDEX=`expr $INDEX + 1`;
done < host_ip


grail 08-20-2012 10:17 AM

My question would be ..what the???

I am not understanding how you ever enter the loop? As you are using 'until' and the string "packet loss" is always in the data it will always return true hence you should never enter the loop?

Ahhhh ... a little testing has revealed a light bulb. When ping finds an ip that it cannot reach it will error, however the grep will always find "packet loss" in the resulting file as it
always exists, hence, the anded (&&) statement is false so until will process the loop again. As this ip will never change until the next is read from the file after the completion
of the until loop, the TRIES will eventually be greater than 3 and so the if is launched.

Firstly I would think it better to simply pipe the ping output to grep as a temporary file serves no purpose here, however, it may be prudent to think about what it is you are actually trying to test for??

ali2011 08-20-2012 11:18 AM

grail: The ping if you are not aware enough, even with unreachable hosts it reports 100% packet loss so the statement is there. In contrary, the RTT value will not be there.

Regarding using until and grep, this is working with reachable hosts (i.e., less than 100% packet loss), BUT not working with unreachable hosts!

PTrenholme 08-20-2012 12:04 PM

Try using packet\ loss instead of "packet loss" in you grep command.

And, per grail's comment, here's a somewhat simpler bash version of your script:
Code:


#!/bin/bash
# Initialize the line counter at zero
INDEX=0
# Read the list of IP addresses
while read IP
do
# Increment the line counter
  INDEX=$((++INDEX))
# Write out the line number and IP
  printf '[%d]\tIP = %-15s' ${INDEX} ${IP}
# Try to ping the address a couple of times
  for ((try=1;try<3;++try))
  do
# Ping the IP from a child process.
    (sudo ping -i 0.025 -c 2 ${IP} | grep -q packet\ loss)
# Did the grep command succeed?
    [ $? -eq 0 ] && break
    printf ' (%d failed)' ${try}
  done
  printf '\n'
done < host_ip

<edit>
And here's the output for a segment of my local network
Code:

]$ bash ali2011.sh
[1]    IP = 192.168.1.101 
[2]    IP = 192.168.1.102 
[3]    IP = 192.168.1.103 
[4]    IP = 192.168.1.104 
[5]    IP = 192.168.1.105 
[6]    IP = 192.168.1.106 
[7]    IP = 192.168.1.107 
[8]    IP = 192.168.1.108 
[9]    IP = 192.168.1.109

</edit>

PTrenholme 08-20-2012 01:53 PM

Here's another look, with an unreachable host in the list. (Note the redirection of the ping error output.)
Code:

#!/bin/bash
# Initialize the line counter at zero
INDEX=0
# Read the list of IP addresses
while read IP
do
# Increment the line counter
  INDEX=$((++INDEX))
# Write out the line number and IP
  printf '[%d]\tIP = %-15s' ${INDEX} ${IP}
# Try to ping the address a couple of times
  for ((try=1;try<3;++try))
  do
# Ping the IP from a child process.
    (sudo ping -i 0.025 -c 2 ${IP} 2>/dev/null | grep -q packet\ loss)
# Did the grep command succeed?
    [ $? -eq 0 ] && break
    printf ' (%d failed)' ${try}
  done
  printf '\n'
done < host_ip

Code:

$ bash ali2011.sh
[1]    IP = 192.168.1.101 
[2]    IP = 192.168.1.102 
[3]    IP = 192.168.1.103 
[4]    IP = 192.168.1.104 
[5]    IP = 192.168.1.105 
[6]    IP = 192.168.1.106 
[7]    IP = www.google.com
[8]    IP = www.AReallyStrangeIS.nonsense (1 failed) (2 failed)
[9]    IP = www.msn.com


ali2011 08-20-2012 02:25 PM

Thanks PTrenholme:

1- I didn't see the point of piping the error message?
2- I need to pipe the ping's output to a ${IP}.loss whether it succeeded or not.
3- Does the [ $? -eq 0 ] && break act as if statement?

ali2011 08-20-2012 02:42 PM

Also the string "packet loss" should always appear no matter ping reached the host or not as I mentioned above! Because of that I can't understand why you have in your output "[8] IP = www.AReallyStrangeIS.nonsense (1 failed) (2 failed)"!

If you pipe the output of that host, you should find the string "packet loss"; however if you replace this string by "rtt" your current output makes sense.

ntubski 08-20-2012 11:29 PM

First off, I'd like to point out that you can probably replace your script with a one line call to nmap. It will not only be simpler, but faster too.


Quote:

Originally Posted by ali2011 (Post 4759470)
Also the string "packet loss" should always appear no matter ping reached the host or not as I mentioned above! Because of that I can't understand why you have in your output "[8] IP = www.AReallyStrangeIS.nonsense (1 failed) (2 failed)"!

Maybe not:
Code:

~$ ping -c 2 -i 0.025 www.AReallyStrangeIS.nonsense
ping: unknown host www.AReallyStrangeIS.nonsense
~$

Quote:

Originally Posted by ali2011
grail: The ping if you are not aware enough, even with unreachable hosts it reports 100% packet loss so the statement is there. In contrary, the RTT value will not be there.

The ping command returns a failed status code if it can't reach the host, since you put && the grep command is not executed in this case. Note that PTrenholme put |, so the grep is always executed.


Quote:

Originally Posted by PTrenholme
Try using packet\ loss instead of "packet loss" in you grep command.

There is no difference between those two.

ali2011 08-21-2012 01:57 AM

ntubski
Regarding the statement I stated "Also the string "packet loss" should always appear no matter ping reached the host or not as I mentioned above!" You said that the string "packet loss may not appear" as in:

Quote:

~$ ping -c 2 -i 0.025 www.AReallyStrangeIS.nonsense
ping: unknown host www.AReallyStrangeIS.nonsense
Your argument is correct in some sense, and in another no. The error in here is not a ping failure as it might appear; IT IS a DNS failure to translate the domain-name to a valid IP address (e.g., not a hidden, private or invalid IP) so the ping didn't even get the chance to be executed, right? Otherwise, ping Always sends packets no matter if they reach destination or not.

In my experiment, however, all hosts in the form of public and numeric IPs (i.e., no DNS task is required on them) under my network so this sort of error will not exist.

ntubski 08-21-2012 01:43 PM

Quote:

Originally Posted by ali2011 (Post 4759819)
In my experiment, however, all hosts in the form of public and numeric IPs (i.e., no DNS task is required on them) under my network so this sort of error will not exist.

Yeah, PTrenholme's experiment was a bit different though, and it seemed like you were commenting on that. I've added more context to where I quoted you, to make that clearer.

grail 08-23-2012 11:02 AM

Quote:

Originally Posted by ali2011 (Post 4759308)
grail: The ping if you are not aware enough, even with unreachable hosts it reports 100% packet loss so the statement is there. In contrary, the RTT value will not be there.

Regarding using until and grep, this is working with reachable hosts (i.e., less than 100% packet loss), BUT not working with unreachable hosts!

So I was away for a couple of days and others have already filled on my behalf, but I thought I would just reiterate:

1. If you read my post again you might see that I agreed with your first point that "packet loss" will always be there (barring ntubski's example)
Quote:

As you are using 'until' and the string "packet loss" is always in the data
2. The reason it works for reachable hosts is because the boolean logic is being satisfied, ie the ping returns success AND (&&) the grep returns success hence the until lip is exited.
However, in the even that the ping is unsuccessful, ie IP not reachable, the grep is never executed as the AND is false if the first expression is false, hence you will receive
an infinite loop and therefore pass TRIES >= 3 so the 'if' is executed

I hope this helps along with the other suggestions of how to fix ;)

btw. In PTrenholme's code, you do not need to separately test the exit code as until (or if in his example) can test it for you :)
Code:

until sudo ping -i 0.025 -c 2 ${IP} | grep -q 'packet loss'
do
    (( ++TRIES == 3 )) && break
done



All times are GMT -5. The time now is 03:19 AM.