当我跳出循环时触发非零退出代码

dim*_*414 3 bash exit-status

我想运行一系列任务,但如果其中任何一个失败就停止,因此我写了(类似):

for task in [TASKS]; do
  process "$task" || break
  commit "$task"
done
Run Code Online (Sandbox Code Playgroud)

这工作正常,但是(如指定的那样)即使我们提前中断,此循环的退出状态也为零。理想情况下break-ing 将能够传达失败。

我知道返回0是 的记录行为break,但我很好奇是否有任何相对干净的解决方法。我能想象的最好的方法是将它包装在一个函数中并设置一个didBreak变量,并将其用作(函数的)退出状态。它可以工作,但感觉过于复杂。

Sté*_*las 6

! break在许多 shell 中使用作品(在我的测试中,除了基于 pdksh 的所有 shell 和shFreeBSD( 设计)):

$ zsh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh88 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ ksh93 -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ dash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ yash -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ bosh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
1
$ pdksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ mksh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
$ posh -c 'for i in x; do ! break; echo "$i"; done'; echo "$?"
0
Run Code Online (Sandbox Code Playgroud)

请注意,它不会errexit在其中任何一个中触发。

去年在 austin-group(POSIX 背后的机构)邮件列表讨论了这个问题。讨论(涉及boshFreeBSDsh和 NetBSD的维护者sh)在达成共识之前就消失了,但普遍的观点似乎是 POSIX 要求这种行为!被记录为否定命令的退出状态,并且break是一个特殊的内置命令以 0 退出状态退出。

但是,如果您将相同的推理return应用于例如,您会看到更少的外壳符合要求。

在 中zsh,您可以return在匿名函数中使用,而不是break

$ () for i in x y; do echo $i; return 1; done
x
$ echo $?
1
Run Code Online (Sandbox Code Playgroud)