如果出现具有退出陷阱的脚本的shell错误,则将退出代码传播给调用者

Eem*_*ola 5 bash exit-code bash-trap

如果带有EXIT陷阱的Bash脚本中出现语法错误,是否可以将退出代码传播给调用者?例如,如果我有:

#! /bin/bash

set -eu

trap "echo dying!!" EXIT

echo yeah
echo $UNBOUND_VARIABLE
echo boo
Run Code Online (Sandbox Code Playgroud)

然后,即使脚本没有真正成功结束,运行它也会提供退出代码0:

$ bash test.sh
yeah
test.sh: line 8: UNBOUND_VARIABLE: unbound variable
dying!!

$ echo $?
0
Run Code Online (Sandbox Code Playgroud)

但是如果我注释掉退出陷阱,则脚本返回1.或者,如果我使用返回非零(例如/bin/false)的命令替换带有未绑定变量的行,则该退出值将按照我希望的方式传播.

tha*_*guy 6

shell以最后执行的命令的结果退出.在你的陷阱案例中echo,这通常会成功返回.

传播你的价值,只需exit用它.

#!/bin/bash

set -eu

die() {
  echo "Dying!!"
  exit "$1"
}

trap 'die $?' EXIT

echo yeah
echo $unbound
echo boo
Run Code Online (Sandbox Code Playgroud)

另请注意,这set -e被认为是有害的 - 它会让您认为如果命令失败,脚本将退出,而这并不总是如此.

  • 问题是旧版本的`bash`(肯定是3.2,可能是早期的4.x)在陷阱执行之前没有出现设置`$?`.`echo yeah`运行正常,所以`$?`为0,但由于未绑定的变量,下一个`echo`甚至没有运行.所以在某种意义上,最后一个运行的命令退出0.在执行陷阱之前,`bash`的更新版本似乎将`$?`设置为1. (4认同)
  • 你的`-e`评论是关于人们不理解什么是"简单的命令"或者是否有其他问题我不知道在这里? (3认同)
  • @EtanReisner 有很多陷阱。`myfunction() { 设置 -e; 错误的; echo "你会认为这不会执行"; }; myfunction && echo oops` 是其中之一 (2认同)

Eem*_*ola 3

此行为与不同的 Bash 版本有关。原始脚本在 Bash 4.2 上按预期工作,但在 3.2 上则不然。将容易出错的代码放在单独的脚本文件中并在子 shell 中运行可以解决早期 Bash 版本中的问题:

#!/bin/bash

$BASH sub.sh
RETVAL=$?

if [[ "$RETVAL" != "0" ]]; then
  echo "Dying!! Exit code: $RETVAL"
fi
Run Code Online (Sandbox Code Playgroud)

子.sh:

set -eu

echo yeah
echo $UNBOUND_VARIABLE
echo boo
Run Code Online (Sandbox Code Playgroud)