如何保存和恢复所有 shell 选项,包括 errexit

Eli*_*iot 10 shell bash

我在各种堆栈交换站点和 unix 帮助论坛上阅读了许多关于如何修改 shell 选项然后恢复它们的问题 - 我在这里找到的最全面的问题是如何“撤消”`set -x`?

收到的智慧似乎是要么保存过的结果set +oshopt -poeval后来恢复到以前的设置。

但是,在我自己使用 bash 3.x 和 4.x 进行的测试中,errexit在执行命令替换时,该选项无法正确保存。

这是显示问题的示例脚本:

set -o errexit
set -o nounset
echo "LOCAL SETTINGS:"
set +o
OLDOPTS=$(set +o)
echo
echo "SAVED SETTINGS:"
echo "$OLDOPTS"
Run Code Online (Sandbox Code Playgroud)

和输出(我修剪了一些不相关的变量):

LOCAL SETTINGS:
set -o errexit
set -o nounset

SAVED SETTINGS:
set +o errexit
set -o nounset
Run Code Online (Sandbox Code Playgroud)

这似乎非常危险。errexit如果任何命令失败,我编写的大多数脚本都依赖于停止执行。我刚刚在我的一个脚本中找到了一个由此引起的错误,本应errexit在最后恢复的函数最终覆盖了它,在脚本运行期间将其设置回默认值off

我希望能够做的是编写可以根据需要设置选项的函数,然后在退出之前正确恢复所有选项。但是好像在子shell中调用的命令替换,errexit是没有继承的。

我不知道如何在set +o不使用命令替换或跳过 FIFO 箍的情况下保存结果。我可以读取,$SHELLOPTS但它不是可写的或不可写的eval格式。

我知道一种替代方法是使用subshel​​l 函数,但这会为能够记录输出以及传回多个变量带来很多麻烦。

可能相关:https : //stackoverflow.com/questions/29532904/bash-subshel​​l-errexit-semantics(似乎有适用于 bash 4.4 及更高版本的解决方法,但我宁愿有一个便携式解决方案)

Gil*_*il' 6

你在做什么应该有效。但是 bash 关闭了errexit命令替换中的选项,因此它保留了除此选项之外的所有选项。这是特定于 bash 和特定于errexit选项的。Basherrexit在 POSIX 模式下运行时会保留。从 bash 4.4 开始,bash 也不会errexit在命令替换中清除(如果shopt -s inherit_errexit有效)。

由于该选项在命令替换内部运行任何代码之前已关闭,因此您必须在外部检查它。

OLDOPTS=$(set +o)
case $- in
  *e*) OLDOPTS="$OLDOPTS; set -e";;
  *) OLDOPTS="$OLDOPTS; set +e";;
esac
Run Code Online (Sandbox Code Playgroud)

如果您不喜欢这种复杂性,请改用 zsh。

setopt local_options
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`bash4.4` 现在具有 `local -`(à la `ash`)作为等效于 `zsh` 的 `setopt localoptions`(或 ksh88 默认情况下所做的) (3认同)
  • 更简单:`OLDOPTS="$(set +o); set -$-"`。 (2认同)