为什么 bash 在 ERR 陷阱中退出 0 时会抑制 stdout?

San*_*man 4 bash

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

./testing.sh:

#!/bin/bash

set -eE

handleerror() {
  echo "TEST"
  exit 0
}
trap "handleerror" ERR

OUTPUT=$(mkdir test/test 2>&1)
Run Code Online (Sandbox Code Playgroud)

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

> ./testing.sh
TEST
Run Code Online (Sandbox Code Playgroud)

以供参考:

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

che*_*ner 5

简短的回答:输出没有被抑制;它是通过命令替换捕获的。更改 的退出状态会更改handleerror它被调用的次数:一次在命令替换内,一次在命令替换。跑起来bash -x testing.sh看看有什么不同。


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

mkdir: test: No such file or directory
TEST
Run Code Online (Sandbox Code Playgroud)

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

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

TEST
Run Code Online (Sandbox Code Playgroud)

由第二次调用产生handleerror