如何在bash命令替换中使用`set -e`?

问题描述 投票:2回答:1

我有一个简单的shell脚本,带有以下序言:

#!/usr/bin/env bash
set -eu
set -o pipefail

我还具有以下功能:

foo() {
  printf "Foo working... "
  echo "Failed!"
  false  # point of interest #1
  true   # point of interest #2
}

作为常规命令执行foo()可以按预期工作:该脚本在#1处退出,因为false的返回码非零,我们使用set -e

我的目标是将函数foo()的输出捕获到一个变量中,并且仅在执行foo()期间发生错误时才打印它。这是我想出的:

printf "Doing something that could fail... "
if a="$(foo 2>&1)"; then
  echo "Success!"
else
  code=$?
  echo "Error:"
  printf "${a}"
  exit $code
fi

脚本不会在#1处退出,并且会执行"Success!"语句的if路径。在true处注释掉#2会导致执行"Error:"语句的if路径。

[bash似乎只是忽略了替换中的set -eif语句只是检查foo()中最后一条命令的返回代码。

问:什么原因导致这种奇怪的行为?

A:这就是bash的工作方式,这是正常行为

Q:有什么方法可以使bash在命令替换内尊重set -e并使它正常工作?

A:您不应为此目的使用set -e

问:在没有set -e的情况下,您将如何实现它(即,仅当执行过程中出现问题时才打印函数的输出)?

我正在使用:

GNU bash,版本5.0.11(1)-发行版(x86_64-apple-darwin18.6.0)

bash shell subshell command-substitution
1个回答
0
投票

您还需要在命令替换中启用set -e

#!/usr/bin/env bash
set -eu
set -o pipefail

foo() {
  printf "Foo working... "
  echo "Failed!"
  false  # point of interest #1
  true   # point of interest #2
}

printf "Doing something that could fail... "
a="$(set -e; foo)"
code=$?
if (($code == 0)); then
  echo "Success!"
else
  echo "Error:"
  printf "${a}"
  exit $code
fi

然后将其用作:

./errScript.sh; echo $?

Doing something that could fail... 1

但是请注意,在外壳程序脚本中使用set -e并不理想,在许多情况下可能无法退出脚本。

Do check this important post on set -e

© www.soinside.com 2019 - 2024. All rights reserved.