Why does while [ 0 ] go into infinite loop?
Single square brackets in the shell is a synonym for test
(either the separate command or the shell built-in), so [ 0 ]
means the same thing as test 0
. test
is for doing comparisons and testing the attributes of files, as you can read about in its manpage. When it isn't given an expression that looks like a comparison, file test, or one of the other operations it can do, it will instead test if the argument is present and a non-empty string. Neither 0
or 1
are really appropriate inputs for test, and as non-empty strings test simply succeeds and your while loop loops forever.
You may want to try instead
while false; do
echo "hello"
done
possibly replacing false
with true
. Or maybe what you want is to use (( ))
:
while (( 0 )); do
echo "hello"
done
Which will behave like most languages, where 0 means failure/false and 1 means success/true.
The value 0 here is not acting as a numeric constant, but as a character string. These tests are all equivalent in their effect of producing a successful termination status:
[ A ]
[ "XYZ" ]
[ 0 ]
these produce a failed termination status:
[ ]
[ "" ]
there is a non-blank argument, which evaluates to logical true. This allows you to do things like:
if [ $UNDER_NUCLEAR_ATTACK ] ; then
launch-missiles -a $DRY_RUN # $DRY_RUN set to "-n" during testing
fi
The variable UNDER_NUCLEAR_ATTACK
is set to any non-blank value to indicate true, or is unset or empty to indicate false.
We can apply the !
operator to reverse the logic:
[ ! a ] # fails: a is nonblank so true; and not true is false.
[ ! ] # succeeds: blank is false, not blank is true.
To evaluate a numeric condition, you have to use numeric test operators:
while [ $A -gt $B ] ; do ...
If A
and B
contain strings that look like decimal integers, they are compared like numbers, and if A
is greater than B
, the loop executes. So suppose that UNDER_NUCLEAR_ATTACK
is not a string-type boolean that is blank or nonblank, but actually a numeric boolean that is either 0
(false) or some other value (true). In that case, we would write the test like this:
if [ $UNDER_NUCLEAR_ATTACK -ne 0 ] ; then ...