Getting the iteration count in WHILE LOOP

bash in RHEL 6.4

I have a requirement in which I want to get the iteration count from a WHILE LOOP.

The below mentioned simple script test.sh works fine. In the below script, the WHILE loop will iterate every 5 seconds infinitely until it greps the string BASKETBALL from /tmp/somestring.txt file. Once it greps the string BASKETBALL, it prints the string in the echo command and the loop is terminated using the break command.

# cat test.sh
export counter=1
while true
do
        if grep -iq BASKETBALL /tmp/somestring.txt
        then
        echo "This loop iterated $counter times before exiting.."
        break
        fi
        sleep 5
        counter=`expr $counter + 1`
done
#
# echo GOLF > /tmp/somestring.txt
# Now, execute the script and it will loop indefinitely as /tmp/somestring.txt file has the string GOLF 
# ./test.sh &
[1] 43208


# #### after few seconds populate /tmp/somestring.txt with the string basketball and the loop will stop iterating

# echo basketball > /tmp/somestring.txt
# This loop iterated 14 times before exiting..

[1]+  Done                    ./test.sh
#

The above script works fine. But, in my real-life script, there is a minor problem. The script itself is executed by root user and then the above portion of the script is executed by another user called appuser after a switch using su command. So, the script will look like below. The double quotes in red mark the beginning and end of commands to be executed by appuser. For this reason, I had to escape the double quotes used in the echo command.

# cat realLife.sh
sudo su - appuser -c "
export counter=1
while true
do
        if grep -iq BASKETBALL /tmp/somestring.txt
        then
        echo \"This loop iterated \$counter times before exiting..\"
        break
        fi
        sleep 5
        counter=`expr $counter + 1`
done
"
#

Although the WHILE LOOP runs fine with the above script, the echo command is always printing "This loop iterated 1 times before exiting.."
even if the loop iterated multiple times.

Demo:

# echo POLO > /tmp/somestring.txt
# Now, execute the script as root
# ./realLife.sh &
[1] 53717
# #### after few seconds populate /tmp/somestring.txt with the string basketball and the loop will stop iterating

# echo basketball > /tmp/somestring.txt
# This loop iterated 1 times before exiting..

[1]+  Done                    ./realLife.sh
#

I guess the double qutotes for the su command is confusing the shell. I wish there was some special variable which provides the loop count. Is there a workaround to fix this issue with realLife.sh script?

The second $counter is not escaped.
Better use ' ' instead of " " and do not escape the " " and $var inside the ' '.
Or rerun the whole script in the sudo context:

if [ "${USER:-$LOGNAME}" = "root" ]
then
  sleep 1 # in case this fails
  exec sudo su - appuser -c "$0 $@"
fi
1 Like

You could also try escaping back quotes..

counter=\`expr \$counter + 1\`
1 Like

Hi MadeinGermany
I cannot use single quotes as there are several SQLs using string literals with single quotes within the su -c block that can cause the shell to get confused.

For eg:
select to_char(sysdate,'DD/MM/YYYY HH24:MI:SS') from dual;

Thank you for pointing out the missing escape character for the second $counter variable

ongoto's suggestion of escaping the backtick seems to fix this issue. The following script has worked. :):b:

I need to check if it works in my real life script. THANK YOU BOTH VERY MUCH.

# cat realLife.sh
sudo su - appuser -c "
export counter=1
while true
do
        if grep -iq BASKETBALL /tmp/somestring.txt
        then
        echo This loop iterated \$counter times before exiting..
        break
        fi
        sleep 5
        counter=\`expr \$counter + 1\`
done
"

Hello John K,

How about counter++ in that, if this works then no need to mess with escaping the quotes.

Thanks,
R. Singh

1 Like

Hi Ravinder
Can you provided some more details on this so that I can google on this.
Any man page available for this ?

Sorry John K I was thinking to do increment the variable but it doesn't work in that way, I think ongoto, MadeInGermany has given good solution for same.

Thanks,
R. Singh

1 Like