user2138149
user2138149

Reputation: 16843

Bash script. While loop with integer comparison never exits

I've written the following minimal example to demonstrate

The following does NOT work:

#! /bin/bash

n=1 m=2

while (( n < m ))
    echo "$n $m"
    (( n=n+1 ))
do
    continue
done

The following DOES work:

#! /bin/bash

n=1 m=2

while true
    echo "$n $m"
    (( n=n+1 ))
do
    if (( n < m ))
    then
        continue
    else
        break
    fi
done

I understand why the second form works. I do not understand why the first form doesn't work.

I wrote these scripts thinking they would be equivalent. (Produce the same output.) However the first loops infinity! Why does this happen?

Upvotes: 0

Views: 3208

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295472

First, a quick look at the documentation:

$ help while
while: while COMMANDS; do COMMANDS; done
    Expand and execute COMMANDS as long as the final command in the
    `while' COMMANDS has an exit status of zero.

Note the exact text: the final command in the while COMMANDS is the one whose exit status counts. We'll return to that later.


In your original code:

while (( n < m ))
    echo "$n $m"
    (( n=n+1 ))
do
    continue
done

...you aren't checking whether (( n < m )) is true as your condition; instead, you're checking whether (( n = n + 1 )) is true.

This is true because everything before the do is composed to form the condition that determines whether to continue running the loop, and the exit status of a series of commands separated by newlines or ;s is the exit status of the last command in that series. The only case where (( n = n + 1 )) would not be true (assuming no contents that can't be coerced to an integer or otherwise cause an error) is if the initial value were below 0, and thus the result were 0 or less.

If you really want all those commands to be inside your condition, you could instead write:

while (( n < m )) && echo "$n $m" && (( n = n + 1 )); do :; done

...though of course that has somewhat different behavior (not 'echo'ing if the comparison has failed).


Consider instead:

while (( n < m )); do
  echo "$n $m"
  (( n++ ))
done

Upvotes: 3

Related Questions