【问题标题】:How to ignore failure of command called through command builtin?如何忽略通过内置命令调用的命令失败?
【发布时间】:2021-09-09 14:43:49
【问题描述】:

我有一个 shell 脚本(在带有 GNU bash 的 macOS 上运行,版本 3.2.57(1)-release),一开始我是 set -e,但我也想忽略一些潜在的故障,以便它们不要结束脚本的执行。我通过将|| ... 附加到相关命令来做到这一点:

#!/bin/sh
set -e
false || echo ignore failure

上述工作并按预期输出ignore failure

但是,如果我通过内置的 command 调用 false 命令,则此策略不起作用 - 一旦 false 失败,以下版本的脚本就会退出,而不打印任何内容:

#!/bin/sh
set -e
command false || echo ignore failure

这是为什么呢?即使在第二种情况下,我如何才能获得忽略失败的期望行为?

(在这个简化的示例中,我当然可以删除 command 内置函数,但在我的实际用例中,它是我无法控制的函数的一部分。)

【问题讨论】:

  • sh (Bourne-shell) 通常不是 bash (Bourne-again shell)。
  • 您使用哪种外壳? bash、sh 还是 zsh?
  • 我想知道它是否将|| 解析为false 的参数。 ( command false ) || echo ignore failure 更好吗?如果你这样做 command echo hello || echo goodbye 会发生什么?
  • @Abelisto 我知道,我正在使用set -e,因为我通常希望在失败时停止执行(在示例压缩的原始脚本中)。但是有一些命令我没有,这就是我使用|| ... 的目的。
  • @Cyrus 在 macOS 上,它们都是 bash(版本 3.2.57(1)-release),但我尝试同时运行脚本,以防 bash 改变行为取决于它以什么程序名称运行。两种情况下的结果都是一样的。

标签: bash macos shell unix sh


【解决方案1】:

为什么command false || echo 会失败?

这似乎是 4.0 以下 bash 版本中的错误。

我下载了old versions 3.2.57 和 4.0,在 Linux 上编译它们,然后运行你的脚本。我可以在 3.2.57 中重现您的问题。在 4.0 中,一切都按预期工作。

奇怪的是,我在 bash 的列表 list of changes 中找不到相应的注释,但如果您搜索 set -e,您会发现其他多个关于 set -e 在其他版本中的行为的错误修复,例如:

本文档详细介绍了此版本 bash-4.4-rc1 和 以前的版本,bash-4.4-beta。
[...]
○。修复了一个错误,该错误导致 set -e 在本应忽略的内建调用其他内建的情况下被兑现。

如何解决问题?

最好的方法是使用更新版本的 bash。即使在 macOS 上,这也不应该成为问题。你可以自己编译或者从brew之类的地方安装。

除此之外,您还可以使用解决方法,例如省略command 或添加子shell ( command false; ) || echo ignore failure(由Nate Eldredge 提供)。无论哪种情况,事情都会变得相当麻烦。由于您不知道错误发生的确切时间,因此您无法确定每次都正确地解决了它。

【讨论】:

  • 有趣,非常感谢你追了这个! OP 的其中一个 cmets 中提到的 subshel​​l 解决方法是否适合您 (( command false ) || echo ignore failure)?它对我有用。如果它也适合您,那么将它添加到答案中可能是有意义的,归功于最初提出它的@NateEldredge?我很乐意接受这个答案——有可能的原因和解决方法,进一步调查可能没有多大意义。
  • 抱歉,页面更新了您的编辑,包括解决方法,就像我发布我之前的评论一样 :)
猜你喜欢
  • 1970-01-01
  • 2018-05-14
  • 2020-05-02
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多