如果特定命令失败,请不要中止脚本



我正在使用以下命令运行我的脚本:

#!/bin/bash -eu

每当出现问题时,它会根据需要中止脚本。但有时我希望其中一个命令最终会失败,我想告诉bash忽略失败条件。在make中,您可以使用方便的以下命令忽略一个命令的状态:

-command

bash有类似的东西吗?唯一想到的是丑陋:

set +e
command
set -e

您可以对命令失败执行无操作,或者将显式 true 条件设置为

command || true

或用于无操作

command || :

这样做会强制命令列表(甚至是管道)在失败时返回退出状态 0。看

true | false
echo $?
1
true | false || true
echo $?
0
true | false || :
echo $?
0

只需在命令前面加上一个!,这样它的退出状态就不会使脚本在使用e运行时退出:

! command

如在 shell 中的命令之前 !的含义是什么?中看到的,具有! command否定给定命令的退出状态,并与set -e一起使用,阻止 shell 退出该行上的退出结果。

来自 Bash 参考手册→管道:

管道中的每个命令都在其自己的子 shell 中执行。管道的退出状态是管道中最后一个命令的退出状态 (...)。如果保留字"!"位于管道之前,则退出状态是如上所述的退出状态的逻辑否定。shell 在返回值之前等待管道中的所有命令终止。

然后我们有关于 4.3.1 内置set的信息:

-e

如果管道(请参阅管道)(可能由单个简单命令(请参阅简单命令)、列表(请参阅列表)或复合命令(请参阅复合命令)组成)返回非零状态,请立即退出。如果失败的命令是紧跟在一段时间或直到关键字之后的命令列表的一部分、if 语句中测试的一部分、在 &&或 || 中执行的任何命令的一部分,则shell 不会退出列出除最后一个 && 或 || 后面的命令之外的命令、管道中除最后一个命令之外的任何命令,或者如果命令的返回状态与 ! 反转

总而言之,引用我自己的答案:

当您有:

set -e
! command1
command2

您正在做的是绕过command1中的set -e标志。 为什么?

  • 如果command1运行正常,它将返回零状态。!会否定它,但set -e不会触发退出,因为它来了 如上所述,从与 ! 反转的返回状态。
  • 如果command1失败,它将返回非零状态。!将否定它,因此该行最终将返回零状态和 脚本将正常继续。

不要认为有

虽然可以编写自己的函数

#!/bin/bash -eu
-(){
set +e
"$@"
set -e
}
- command
echo got here

可能想要使用函数名称,因为 bash 中已经使用了-

正如Chepner指出的那样,它仅适用于简单的命令,不适用于管道或列表。

最新更新