【问题标题】:Bash: Trap ERR does not work when pipe operator is usedBash:使用管道运算符时陷阱 ERR 不起作用
【发布时间】:2015-02-17 06:06:25
【问题描述】:

我正在尝试将来自 stdout 和 stderr 的所有内容记录到日志文件中,并且仍然保留控制台。为此,我只是将:|& tee -a log_file.log 附加到每个命令。
但是,如果脚本期间发生任何错误,我也想运行自定义命令。为此,我在脚本的开头添加了以下内容:trap "echo Non-zero exit code detected" ERR
问题是通过使用管道运算符,陷阱中的回显不再执行。

脚本 1,没有管道:

$cat test.sh
#!/bin/bash

trap "echo Non-zero exit code detected!" ERR

function fail_please()
{
    echo "Returning non-zero exit code!"
    return 1
}

fail_please 

输出 1:

$ ./test.sh 
Returning non-zero exit code!
Non-zero exit code detected!

脚本 2,带有管道:

$ cat test.sh
#!/bin/bash

trap "echo Non-zero exit code detected!" ERR

function fail_please()
{
    echo "Returning non-zero exit code!"
    return 1
}

fail_please |& tee log_file.log 

输出 2:

$ ./test.sh
Returning non-zero exit code!
$ cat log_file.log 
Returning non-zero exit code!

在输出 2 中,消息“检测到非零退出代码!”不见了。知道为什么吗? 谢谢!

【问题讨论】:

  • ERR 陷阱针对“简单命令”触发,管道不是简单命令。它可能会触发整个管道的结果(我不确定),并且您可以通过设置pipefail 获得更接近您想要的结果。这是人们通常不建议使用 set -e 的原因之一,因为它有这样令人惊讶的细节。
  • 谢谢!我添加了set -o pipefail,它起作用了。但是,我不太明白为什么不推荐set -e。它还有其他警告吗?另外,请添加答案以接受它。
  • set -e 与您的 ERR 陷阱有类似的警告。它不会在您期望的所有情况下触发。其中一些情况在您原本可以工作的代码之外。
  • 只是澄清一下,在脚本 2 中,通过设置 pipefail,管道的返回码仍然是 0(因为 tee 返回 0),但它可以让我的 ERR 陷阱以防万一第一个命令失败。这是正确的吗?
  • 我刚刚添加了一条评论,说明为什么 pipefail 对我的答案有效,但是是的,它设置返回到最后一个失败的命令的退出状态,而不是始终是最后一个命令的退出状态正在筹备中。

标签: linux bash pipe tee bash-trap


【解决方案1】:

ERR 陷阱针对“简单命令”触发,管道不是简单命令。

它可能会触发整个管道的结果(我不确定),并且您可以通过设置 pipefail 获得更接近您想要的结果。

(注意:这是人们通常不建议使用set -e 的原因之一,因为它有这样令人惊讶的细节。)

pipefail 起作用的原因是,通常管道的返回状态是最后一个命令的返回,但带有pipefail 它成为最后一个失败命令的返回状态。

管道的返回状态是最后一条命令的退出状态, 除非启用了 pipefail 选项。如果启用 pipefail,则 管道的返回状态是最后(最右边)命令的值 以非零状态退出,或者如果所有命令都成功退出则为零 - 完全。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-07
    • 1970-01-01
    • 2016-12-18
    相关资源
    最近更新 更多