为啥在 ERR 陷阱中退出 0 时 bash 会抑制标准输出?

Posted

技术标签:

【中文标题】为啥在 ERR 陷阱中退出 0 时 bash 会抑制标准输出?【英文标题】:Why does bash suppress stdout when exit 0 in ERR trap?为什么在 ERR 陷阱中退出 0 时 bash 会抑制标准输出? 【发布时间】:2019-10-07 21:15:10 【问题描述】:

我正在尝试在 bash 中设置 ERR 陷阱,并注意到一些奇怪的行为。如果退出代码为0,则当我运行此脚本时,Bash 似乎不会将我的echo 命令输出到控制台,但是,如果退出代码为非零,则输出文本。这是bash中的错误吗?或者对此有什么解释?

./testing.sh:

#!/bin/bash

set -eE

handleerror() 
  echo "TEST"
  exit 0

trap "handleerror" ERR

OUTPUT=$(mkdir test/test 2>&1)

如果我运行上面的脚本,它什么也不输出。如果我将exit 0 行更改为exit 1,我会看到以下内容:

> ./testing.sh
TEST

供参考:

> bash --version
GNU bash, version 3.2.57(1)-release (x86_64-apple-darwin18)
Copyright (C) 2007 Free Software Foundation, Inc.

【问题讨论】:

【参考方案1】:

简答:输出没有被抑制;它由命令替换捕获。更改handleerror 的退出状态会更改它被调用的次数:一次在命令替换内部,一次在在外部。运行bash -x testing.sh 看看有什么不同。


您必须考虑何时实际调用 handlerrormkdir 的失败会触发调用,并且由于在命令替换中调用了handleerror,因此它的输出被捕获并分配给OUTPUT。如果你在脚本末尾添加echo "$OUTPUT",你会看到

mkdir: test: No such file or directory
TEST

作为脚本的输出。执行此行是因为 handleerror 的 0 退出状态阻止 set -e 提前退出脚本。

现在,将 exit 0 更改为 exit 1。序列开始相同:mkdir 失败,handleerror 被调用,其输出被命令替换捕获。但是,现在handleerror 本身的退出状态为1,这使得命令替换的退出状态以及赋值语句也为1。这做了两件事:它导致set -eecho "$OUTPUT" 运行之前中止脚本,它导致handleerror 运行 时间。现在,当您运行脚本时,您看到的只是

TEST

第二次调用handleerror

【讨论】:

感谢您的洞察力。我认为我的心智模型与这里实际发生的情况不符。是时候阅读命令替换了。

以上是关于为啥在 ERR 陷阱中退出 0 时 bash 会抑制标准输出?的主要内容,如果未能解决你的问题,请参考以下文章

语法错误时不执行“ERR”陷阱

在 bash 中退出并显示错误消息(单行)

为啥使用 += 在 bash 中存储命令的退出状态?

返回与 bash 脚本中返回的命令不同的退出代码

使用陷阱终止bash中的函数

为啥重定向输出时测试退出状态不起作用?