保留 set -e 里面的设置 ||要么 &&

Keep set -e setting inside || or &&

我有一个简单的脚本,其中的简单功能可能会导致错误。让我们定义这个函数,并把它打碎:

brokenFunction () {
    ls "non-existing-folder"
}

如果我们在检测它是否损坏的块中执行此函数,它会很好地工作:

brokenFunction || printf "It is broken\n"

打印"It is broken"

现在,让我们通过在末尾添加正确的命令来使函数更复杂一些:

#!/bin/sh

brokenFunction () {
    ls "non-existing-folder"
    printf "End of function\n"
}

brokenFunction || printf "It is broken\n"

此脚本打印:

$ ./script.sh 
ls: cannot access 'non-existing-folder': No such file or directory
End of function

虽然我希望函数在 printf 语句之前停止,并显示下一个块 "It is broken".

确实,如果我检查 brokenFunction 的退出状态代码,它是 0。

我尝试将 set -e 添加到脚本的顶部。行为仍然相同,但如果在没有 || 的情况下调用 brokenFunction 的退出代码现在变为 2。如果用它调用,状态码仍然是 0.

有什么方法可以将 set -e 设置保留在使用 || 调用的函数中吗?

编辑:我刚刚意识到示例中的函数是无用的。我用一个简单的块和一个条件遇到了同样的问题。

#!/bin/sh
set -e
{
    ls "non-existing-dir"
    printf "End of block\n"
} || {
    printf "It is broken\n"
} 

打印

$ ./script.sh 
ls: cannot access 'non-existing-dir': No such file or directory
End of block

man bash 中所写,set -e 在某些情况下会被忽略。 ||&& 之前的命令就是这样的上下文。

trap 看起来像是一个可能的解决方案。使用 trap 的最后一个脚本的有效替代方案如下所示:

#!/bin/sh
abort () {
    printf "It is broken\n"
}
trap 'abort' ERR
(
    set -e
    false
    printf "End of block\n"
)
trap - ERR

这里有几点需要注意:

  • trap 'abort' ERRabort 函数绑定到任何引发的错误;
  • 损坏的块在子shell中执行有两个原因。首先是将 set -e 设置保留在块内并限制边框效果。其次是在出错时退出此子 shell(set -e 效果),而不是整个脚本;
  • trap - ERR 最后重置 trap 绑定,这意味着脚本的以下部分像以前一样执行。

为了测试边框效果,我们可以添加之前不起作用的部分:

#!/bin/sh
abort () {
    printf "It is broken\n"
}

trap 'abort' ERR
(
    set -e
    false
    printf "End of block\n"
)
trap - ERR

{   
    false
    printf "End of second block\n"
} || {
    printf "It is broken too\n"
}

打印:

It is broken
End of second block