Bash 怪异:与条件相关的算术表达式的退出代码。 true/false 对比 success/failure

Bash Weirdness: Exit Codes of Arithmetic Expressions in Relation to Conditionals. true/false vs. success/failure

根据 bash man 页面,

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.

我试图弄清楚 bash 如何解释出现在列表 1 末尾的算术表达式的退出代码。我开始了一些实验:

$ 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.

因此,在修复两个错误后(感谢@Barmar),有一个基于 while 循环查看退出代码的一致解释。仍然不清楚的是为什么 ((0)) 的退出代码是失败,而 ((1)) 的退出代码是成功。

我在尝试捕获 while 条件下函数的退出代码以供循环中断时使用时遇到了这个问题:

while <function>; do
    <stuff>
done

# I need the exit code of <function> here.

所以,也许这样:

while <function>; ((! (RESULT=$?) )); do  # alternative ! (( RESULT=$? ))
    <stuff>
done

bash 所做的是将计算结果为 1((1)) 与“真相”相关联。然后它通过 return 成功退出代码 0 使其与退出代码一致。同样,它将计算结果为 0((0)) 关联到“false”。它们通过 return 失败的退出代码 1.

使其与退出代码一致

这可能看起来令人困惑,因为毕竟两个评估 ((.)) 都是“成功的”,但这是使表示 true/false 的算术表达式的值与 [=26= 一致的 hack ] 的 success/failure 退出代码,并使 if ...; then ...; fiwhile ...; do ...; done 等条件表达式正常工作。

任何计算结果为零的都是假的,任何不是零的都是真的。

这意味着您可以执行以下操作:

while :; do
    ((c++%5)) || ((val=RANDOM))
    echo "$val changes every 5 iterations"
    sleep 0.5
done

负数不为零:

$ ((20-30)); echo $?
0
$ ((20-20)); echo $?
1
$ ((20-10)); echo $?
0

对于((! 0)),0的逻辑非为1,((1))return为真(0)。对于 !((0)),return 值 false (1) 被(非算术)运算符 ! 否定,导致算术子 shell 的 return 值为真( 0) 而不是假的。