Bash – null string as command in while loop: empty/null-command

bashsyntax

I'm wondering how the while loop evaluates its loop condition. In the man page it is written:

while list-1; do list-2; done

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.

and

Lists

A list is a sequence of one or more pipelines separated by one of the operators ;, &, &&, or ||, and optionally terminated by one of ;, &, or .

and

Pipelines

A pipeline is a sequence of one or more commands separated by one of the control operators | or |&. The format for a pipeline is:

         [time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]

This means:

while <single-command>; do <list>; done;

is valid syntax. The list is executed as long as <single-command> returns 0. If I run a while loop, like this, I get (obviously) errors:

$while aaa; do echo "foo"; done;
If 'aaa' is not a typo you can use command-not-found to lookup the package that contains it, like this:
cnf aaa

$while ; do echo "foo"; done;
Absolute path to '' is '/usr/sbin/', so running it may require superuser privileges (eg. root).

$while ""; do echo "foo"; done;
Absolute path to '' is '/usr/sbin/', so running it may require superuser privileges (eg. root).

To my surprise, using an unitialized variable bar as <single-command>, I run into an infinite loop:

$while $bar; do echo "foo"; done;
foo
foo
foo
...

This means, bar gets parameter-expanded to an empty string(?), gets executed(?) and always returns 0. But why doesn't my second error-example work equivalently? Interestingly:

$while "$bar"; do echo "foo"; done;
Absolute path to '' is '/usr/sbin/', so running it may require superuser privileges (eg. root).

doesn't work. This is equivalent to my third error-example. $bar gets expanded to an empty string and the unescaped quotes remain.

So my question is: How does the shell(bash in my case) interpret the

$while $bar; do echo "foo"; done;

command which results in an endless-loop?

Update:

I found out that the null-command (does nothing, returns 0) isn't that hard to simulate. The null command corresponds to : . So the non-terminating while-loop can be written equivalently as:

while :; do echo "foo"; done;

Best Answer

The while instruction is followed by the command from which to evaluate the return code to determine if it should loop or not. It proceeds if the return value is 0.

Referring to an uninitialized variable is identical to having it initialized to ''.

Since running an empty command causes no error, it returns the corresponding return code (0):

$ foo=''
$ $foo
$ echo $?
0

That is normal behavior since the shell would otherwise give an error each time you press enter without typing anything.

Note that this differs from specifying an empty string which the shell identifies as an issue:

$ ''
-bash: : command not found
$ echo $?
127
Related Question