Home > Blockchain >  Bash Weirdness: Exit Codes of Arithmetic Expressions in Relation to Conditionals. true/false vs. suc
Bash Weirdness: Exit Codes of Arithmetic Expressions in Relation to Conditionals. true/false vs. suc

Time:11-13

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.

  • Related