LinuxQuestions.org
Download your favorite Linux distribution at LQ ISO.
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices

Reply
 
Search this Thread
Old 11-14-2012, 06:15 PM   #1
wolverene13
Member
 
Registered: May 2010
Location: Matiland, FL
Distribution: Debian Squeeze
Posts: 49

Rep: Reputation: 0
infinite nested while loop


Hi,

After much searching, I've decided to resort to the tried and true LQ Forums. Here's what I'm trying to accomplish:

I need to ping several nodes one at a time with a single ping, over and over. When it reaches the bottom of the list, I want it to go back to the top and do it over again, infinitely. Here's what I tried so far:

Code:
#!/bin/bash

while true
do
#useless use of cat, I know
cat ~/tunnel_ips.txt | while read NODE 
do
rc=$?
ping -c 1 -w 1 $NODE > /dev/null
if [ $rc -eq 0 ]; then
echo "$NODE alive"
else
echo "$NODE failed"
fi
done >> pingscript-output.txt
done
This appears to work, however, it created a bit of a problem where the CPU was spiking after a while. I investigated and found out that the script didn't work the way I thought it would, as it basically created multiple instances of the script process over and over again without killing the previous one as I assumed it would. So, I ended up slamming the server. I know it's because of the nesting of the while loops, combined with the "while true" statement, but I can't really think of another way to do it. Anyone got any ideas?

Thanks in advance,

wolverene13

Last edited by wolverene13; 11-14-2012 at 06:54 PM. Reason: corrected rc eq 0 line
 
Old 11-14-2012, 07:53 PM   #2
towheedm
Member
 
Registered: Sep 2011
Location: Trinidad & Tobago
Distribution: Debian Squeeze
Posts: 585

Rep: Reputation: 118Reputation: 118
I busted my brains trying to figure out where your script calls itself. Finally, decided to run it with one modification. The variable $? returns the exit status of the last command, or according to BASH's textinfo pages:
Quote:
? Expands to the exit status of the most recently executed fore‐
ground pipeline.
As it is in your script it will return the exit status of the read NODE command. Moving it to after the ping command and running your script did not create (according to top) any additional processes.

You can also do away with the if-then statement by using the && and || commands. Also redirect both stderr and stdout to /dev/null.

Here my modified script:
Code:
#!/bin/bash

while true; do
  while read NODE ; do
    ping -c 1 -w 1 $NODE &>/dev/null && echo "$NODE alive" || echo "$NODE failed"
  done < tunnel_ips.txt >> pingscript-output.txt
done
exit
Or, if you must use if-then:
Code:
if ping -c 1 -w 1 $NODE &>/dev/null ; then
  echo "$NODE alive"
else
  echo "$NODE failed"
fi
I would also recommend a timestamp:
Code:
echo "$(date +%H":"%M) $NODE alive"

Last edited by towheedm; 11-14-2012 at 08:01 PM.
 
Old 11-14-2012, 08:04 PM   #3
wolverene13
Member
 
Registered: May 2010
Location: Matiland, FL
Distribution: Debian Squeeze
Posts: 49

Original Poster
Rep: Reputation: 0
Quote:
Originally Posted by towheedm View Post
I busted my brains trying to figure out where your script calls itself. Finally, decided to run it with one modification. The variable $? returns the exit status of the last command, or according to BASH's textinfo pages:


As it is in your script it will return the exit status of the read NODE command. Moving it to after the ping command and running your script did not create (according to top) any additional processes.

You can also do away with the if-then statement by using the && and || commands. Also redirect both stderr and stdout to /dev/null.

Here my modified script:
Code:
#!/bin/bash

while true; do
  while read NODE ; do
    ping -c 1 -w 1 $NODE &>/dev/null && echo "$NODE alive" || echo "$NODE failed"
  done < tunnel_ips.txt >> pingscript-output.txt
done
exit
Or, if you must use if-then:
Code:
if ping -c 1 -w 1 $NODE &>/dev/null ; then
  echo "$NODE alive"
else
  echo "$NODE failed"
fi
I would also recommend a timestamp:
Code:
echo "$(date +%H":"%M) $NODE alive"
Awesome! Both solutions worked perfectly! Thanks! I'm confused though - when using the || operator, how does it know whether to echo failed or alive?

Last edited by wolverene13; 11-14-2012 at 08:05 PM. Reason: clarified statement
 
Old 11-14-2012, 08:32 PM   #4
towheedm
Member
 
Registered: Sep 2011
Location: Trinidad & Tobago
Distribution: Debian Squeeze
Posts: 585

Rep: Reputation: 118Reputation: 118
From BASHs info pages:
Quote:
Lists
A list is a sequence of one or more pipelines separated by one of the
operators ;, &, &&, or ⎪⎪, and optionally terminated by one of ;, &, or
<newline>.

Of these list operators, && and ⎪⎪ have equal precedence, followed by ;
and &, which have equal precedence.

A sequence of one or more newlines may appear in a list instead of a
semicolon to delimit commands.

If a command is terminated by the control operator &, the shell exe‐
cutes the command in the background in a subshell. The shell does not
wait for the command to finish, and the return status is 0. Commands
separated by a ; are executed sequentially; the shell waits for each
command to terminate in turn. The return status is the exit status of
the last command executed.

AND and OR lists are sequences of one of more pipelines separated by
the && and ⎪⎪ control operators, respectively. AND and OR lists are
executed with left associativity. An AND list has the form

command1 && command2

command2 is executed if, and only if, command1 returns an exit status
of zero.

An OR list has the form

command1 ⎪⎪ command2

command2 is executed if and only if command1 returns a non-zero exit
status. The return status of AND and OR lists is the exit status of
the last command executed in the list.
So basically:
Code:
command1 && command2 || command3
If command1 returns an exit status of 0, command2 gets executed and the lists ends.
It becomes:
Code:
command1 && command2
If command1 returns an exit status other than 0, then command2 does not get executed. Instead command3 gets executed:
Code:
command1 || command3
So basically:
Code:
command1 && command2 || command3
says: If command1 succeeds then exucute command2 else execute command3, which is why it's the same as:
Code:
if command1 ; then
  command2
else
  command3
fi
Hope I explained it properly.
 
1 members found this post helpful.
  


Reply

Tags
bash, infinite, list, loop


Thread Tools Search this Thread
Search this Thread:

Advanced Search

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] Bash - While Loop reading from two lists simultaneously - nested while loop wolverene13 Programming 11 10-01-2011 05:00 PM
[SOLVED] infinite loop that isnt infinite? frieza Programming 2 10-27-2010 02:16 PM
infinite loop on fclose()? joe2748 Programming 10 03-05-2010 08:09 PM
Infinite Loop ewt3y Programming 3 08-16-2005 09:48 AM
infinite loop beginner_84 Programming 5 08-15-2004 02:32 AM


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

Main Menu
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
identi.ca: @linuxquestions
Facebook: linuxquestions Google+: linuxquestions
Open Source Consulting | Domain Registration