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

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

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

while <function>; do 
    <stuff> 
done 

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

答案1

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

while rmdir FOO; ss=$?; [[ $ss -eq 0 ]]
do
    echo in loop
done
echo "out of loop with ?=$? but ss=$ss"

输出

rmdir: failed to remove 'FOO': No such file or directory
out of loop with ?=0 but ss=1

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

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

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

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

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

答案2

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

err=0
while true
do
    <function>
    (( (err=$?) > 0 )) && break
    <stuff>
done
echo "$err"

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

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

答案3

创建一个包装函数,用函数的退出代码的结果设置一个变量。例子:

e=0

# file does not exist
foo() { 
  rm xyz
}

baz() { 
  foo
  e=$?
  [[ $e -ne 0 ]] && return 1
  return 0
}

# create a file
touch xyz
while baz; do
  # first loop succeeds, the file exists
  # second loop exits with error, file doesn't exists
  echo in loop
done
in loop
rm: cannot remove 'xyz': No such file or directory
# then
$ echo $e
1

答案4

使用zsh,您可以return从匿名函数中使用:

() while ((1)) {
  <function> || return
  <stuff>
}
print $?

对于任何类似 Bourne 的 shell,您始终可以使用命名函数:

repeat_until_fail()
  while true; do
    <function> || return
    <stuff>
  done

repeat_until_fail
echo "$?"

相关内容