当 Bash“while”循环终止时需要条件函数的退出代码

Dia*_*gon 16 bash shell-script error-handling

我试图获取我在 Bash 循环的“条件”部分中重复调用的函数的退出代码while

while <function>; do 
    <stuff> 
done 
Run Code Online (Sandbox Code Playgroud)

当此循环由于错误而终止时,我需要 的退出代码<function>。关于如何得到它有什么想法吗?

roa*_*ima 22

您可以捕获条件的退出值并将其向前传播:

while rmdir FOO; ss=$?; [[ $ss -eq 0 ]]
do
    echo in loop
done
echo "out of loop with ?=$? but ss=$ss"
Run Code Online (Sandbox Code Playgroud)

输出

rmdir: failed to remove 'FOO': No such file or directory
out of loop with ?=0 but ss=1
Run Code Online (Sandbox Code Playgroud)

在本例中,退出状态rmdir FOO已被捕获在变量中ss,并且为1。(尝试替换rmdir FOO( exit 4 )。你会发现ss=4。)

这是如何运作的?请记住,语法实际上是while list-1; do list-2; done,而不是更常见的期望while command; do list; done。可以list-1是一系列以分号分隔的命令,并且文档指出“只要列表中的最后一个命令返回退出状态为零,该while命令就会连续执行该列表list-2list-1。 ”

作为看起来混乱的while条件的另一种表示方式,可以在表达式内部分配变量(( ... )),然后使用结果。这给出了更难阅读但更紧凑的分配和测试结构:

while rmdir FOO; ((! (ss=$?)))
do
    echo in loop
done
echo "out of loop with ?=$? but ss=$ss"
Run Code Online (Sandbox Code Playgroud)

或者您可以使用while rmdir FOO; ! (( ss=$? )). 这些之所以有效,是因为 ((1)) 的算术计算结果为 1,这通常与 true 相关,因此该计算的退出代码为 0(成功)。另一方面,((0)) 的算术计算结果为 0,这通常与 false 相关,因此该计算的退出代码为 1(失败)。这可能看起来很令人困惑,因为毕竟两个评估((.))都是“成功”的,但这是一种 hack,使表示 true/false 的算术表达式的值与 bash 的成功/失败退出代码保持一致,并创建条件表达式,如if ...; then ...; fiwhile ...; do ...; done等,无论是基于退出代码还是算术值,都可以正常工作。

  • @Diagon `(( (ss=$!) ))` 没有子 shell;这都是表达式评估。类似于 `(( (1+2)*3 ))`,其中 `*` 不是文件名 glob,而是乘法符号 (2认同)
  • 是的,我找到了。在“算术求值”下,“运算符按优先级顺序求值。括号中的子表达式首先求值,并且可能会覆盖上面的优先级规则。” (2认同)

Adm*_*Bee 5

实现此目的的一种方法是显式进行测试,而不是将其委托给while. 因此,应该执行以下操作:

err=0
while true
do
    <function>
    (( (err=$?) > 0 )) && break
    <stuff>
done
echo "$err"
Run Code Online (Sandbox Code Playgroud)

在(先验无限)循环开始时,您将“手动”执行条件命令并存储退出代码,检查它,如果它非零(表示失败)则退出循环。仅当它为零时,您才执行“实际”循环代码。

语法可以“压缩”,因为(正如 @roaima 所指出的)您可以在(( ... ))算术测试构造中进行变量赋值。