According to the bash
man
page,
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.
I'm trying to make sense of how bash is interpreting the exit codes of arithmetical expressions when they appear at the end of list-1. I started with some experiments:
$ echo $((1))
1
$ ((1)); echo $?
0
$ echo $((! 1))
0
$ ((! 1)); echo $? # Hm, what does this exit code mean?
1
$ while ((1)); do echo "yes"; break; done
yes
# This could be responding to either the exit code of ((1))
# or to it's value, 1 meaning true
$ while ((! 1)); do echo "yes"; break; done
# This could be responding to either the exit code of ((! 1)),
# or to it's value, 0 meaning false
$ while ! ((1)); do echo "yes"; break; done
# this ! should change the exit code, not the value,
# so it appear to be responding to the exit code
$ echo $((0))
0
$ ((0)); echo $? # Hm, what does this exit code mean?
1
$ echo $((! 0)))
1
$ ((! 0)); echo $?
0
$ while ((0)); do echo "yes"; break; done
# This could be responding to either the exit code of ((0))
# or to it's value, 0 meaning false
$ while ((! 0)); do echo "yes"; break; done
yes
# This could be responding to either the exit code of ((! 0))
# or to it's value, 1 meaning true
$ while ! ((0)); do echo "yes"; break; done
yes
# this ! should change the exit code, not the value,
# so it appears to be responding to the exit code.
So, after fixing two errors (thanks @Barmar), there is a consistent interpretation based on the while loop looking at exit codes. What remains obscure is why the exit code of ((0))
is failure, and the exit code of ((1))
is success.
I came across this while trying to capture exit codes of functions in the while condition for use when the loop breaks:
while <function>; do
<stuff>
done
# I need the exit code of <function> here.
So, perhaps this way:
while <function>; ((! RESULT=$? )); do # alternative ! (( RESULT=$? ))
<stuff>
done
CodePudding user response:
What bash
is doing is associating ((1))
, which evaluates to 1
, to "truth". It then makes that consistent with exit codes by returning an exit code of success, 0
. Similarly, it is associating ((0))
, which evaluates to 0
, to "false". It them makes that consistent with exit codes by return the exit code of failure, 1
.
This may seem confusing, as after all both evaluations ((.))
are "successful", but this is a hack to bring the value of arithmetic expressions representing true/false in line with bash's exit codes of success/failure, and make conditional expressions like if ...; then ...; fi
, while ...; do ...; done
, etc, work correctly.
CodePudding user response:
Anything that evaluates to zero is false, anything that does not is true.
It means you can do things like:
while :; do
((c %5)) || ((val=RANDOM))
echo "$val changes every 5 iterations"
sleep 0.5
done
Negative numbers are not zero:
$ ((20-30)); echo $?
0
$ ((20-20)); echo $?
1
$ ((20-10)); echo $?
0
For ((! 0))
, the logical negation of 0 is 1, and ((1))
returns true (0). For !((0))
, the return value false (1), is negated by the (non arithmetic) operator !
, causing the return value of the arithmetic subshell to be true (0) instead of false.