pmverma
pmverma

Reputation: 1703

Bash script unexpected result for while loop

I have following bash script to stop Apache server. I am not getting error but an unexpected result.

#!/bin/bash

/etc/init.d/httpd stop
if [[ $? -ne 0 ]]
then
    exit 1
fi
RTN=10
while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do
    sleep 5
    RTN=`ps -C httpd | wc -l`
    RTN=$(( RTN - 1 ))
echo "After" $RTN
done 

exit 0

I got the following answer which I do not expect to be, with an infinite printing:

Before 10
After 0

Before 0
After 0

Before 0
After 0

I expect to print:

Before 10
After -1 
#and exit here

Could anybody please tell me what is happening?

Upvotes: 1

Views: 214

Answers (2)

Jahid
Jahid

Reputation: 22448

Your ps -C httpd command always returns a line: PID TTY TIME CMD (basically the heading of the ps output) which is counted by wc -l as 1 when there is no process running. If httpd was running the line count would be greater than 1.

Thus $((RTN -1)) becomes 0.

Edit:

I notice, you have an error in your while loop:

while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do

Change it to:

while [[ $RTN -gt 0 ]]
do
echo "Before" $RTN

Upvotes: 1

paxdiablo
paxdiablo

Reputation: 882676

This doesn't work the way you seem to think it does:

while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do

You want the echo to come after the do. With it before the do, it's part of the list-1 condition rather than the list-2 body. And, as per the bash docs (my bold):

The while command continuously executes the list list-2 as long as the last command in the list list-1 returns an exit status of zero.

You can see the difference between the following script, similar to yours:

#!/usr/bin/bash
RTN=2
while [[ $RTN -gt 0 ]]
echo "Before" $RTN
do
    sleep 1
    RTN=$(( RTN - 1 ))
echo "After" $RTN
done

which outputs (ad infinitum):

Before 2
After 1
Before 1
After 0
Before 0
After -1
Before -1
After -2
Before -2

When you move the echo to inside the body:

#!/usr/bin/bash
RTN=2
while [[ $RTN -gt 0 ]]
do
    echo "Before" $RTN
    sleep 1
    RTN=$(( RTN - 1 ))
    echo "After" $RTN
done

it then terminates properly:

Before 2
After 1
Before 1
After 0
<returns to prompt>

Once that change is made, the loop terminates correctly, given the values being generated by your ps command.


Additionally, if you want to find out what's in the process list (and probably causing an result of zero rather than negative one), output the process list before checking the count:

:
ps -C httpd                 # Add this line temporarily.
RTN=`ps -C httpd | wc -l`
:

Upvotes: 2

Related Questions