0

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?

1 Answer 1

3

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
Sign up to request clarification or add additional context in comments.

4 Comments

The madness of bash - thanks this cleared things up nicely!
@user3728501, if you wrote while(n<m, printf("%d %d\n", n, m), n++) { continue; } in C you'd have the exact same bug. This was simply sloppy coding, not bad language design.
It's not necessarily good or bad language design. I just didn't understand the syntax. Misunderstanding syntax != sloppy coding.
Sorry -- we get a lot of complaints about syntax here, and I read the "madness" comment to be onesuch. There is a lot of awfulness inherited by POSIX-compliant shells, often from design decisions made in the 70s; no need to make it out to be worse than the status quo even in the places where it's on par! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.