Does Linux Bash have a do-while loop?

Willem Van Onsem picture Willem Van Onsem · Jan 4, 2015 · Viewed 20.6k times · Source

After some search on the Internet, it appears that Bash doesn't have a do-while loop.

Is this correct? Is there a reliable source to confirm this (the lack of evidence that there is a do-while loop is not an argument that there isn't one, perhaps a statement is only unpopular)?

Is it possible to define directives oneself and thus implement a do-while loop? There is an algorithmic way to transform a do-while-loop in a while-loop, but this is not the scope of this question.

Answer

rici picture rici · Jan 4, 2015

bash (or Posix shells in general) don't have an explicit syntax for a post-test loop (commonly known as a "do-while" loop) because the syntax would be redundant. The while compound statement allows you to write pre-test, post-test or mid-test loops, all with the same syntax.

Here's the semantics of a shell while loop, from Posix:

The format of the while loop is as follows:

while compound-list-1
do
  compound-list-2
done

The compound-list-1 shall be executed, and if it has a non-zero exit status, the while command shall complete. Otherwise, the compound-list-2 shall be executed, and the process shall repeat.

A "compound list" is a sequence of commands; the exit status of a compound list is the exit status of the last command in the list.

That means that you could think of a while loop as being written as follows:

while
  optional-pre-test-compound-list
  condition
do
  post-test-compound-list
done

That is, there is no requirement that the condition to be tested immediately follows the while keyword. So the equivalent to the C syntax:

do statements while (test);

is

while statements; test do :; done

The : between the do and the done is required, because the shell grammar does not allow empty statements. Since : is not a metacharacter, it must have whitespace or a metacharacter before and after it; otherwise, it would be parsed as part of the preceding or succeeding token. Since it's parsed as a command, it also needs a semicolon or newline after it; otherwise the done is treated as an argument to :.