在带有函数的 bash 中使用 set -e / set +e

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/27793264/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 21:49:21  来源:igfitidea点击:

Using set -e / set +e in bash with functions

bashshell

提问by Michel Müller

I've been using a simple bash preamble like this in my scripts:

我一直在我的脚本中使用这样一个简单的 bash 序言:

#!/bin/bash
set -e

In conjunction with modularity / using functions this has bitten me today.

结合模块化/使用功能,这让我今天很头疼。

So, say I have a function somewhere like

所以,说我在某个地方有一个功能

foo() {
  #edit: some error happens that make me want to exit the function and signal that to the caller 
  return 2
}

Ideally I'd like to be able to use multiple small files, include their functions in other files and then call these functions like

理想情况下,我希望能够使用多个小文件,将它们的函数包含在其他文件中,然后调用这些函数,例如

set +e
foo
rc=$?
set -e

. This works for exactly two layers of routines. But if foo is also calling subroutines like that, the last setting before the return will be set -e, which will make the script exit on the return - I cannot override this in the calling function. So, what I had to do is

. 这正好适用于两层例程。但是,如果 foo 也像这样调用子例程,则返回之前的最后一个设置将是set -e,这将使脚本在返回时退出 - 我无法在调用函数中覆盖它。所以,我必须做的是

foo() {
  #calling bar() in a shielded way like above
  #..      

  set +e
  return 2
}

Which I find very counterintuitive (and also not what I want - what if in some contexts I'd like to use the function without shielding against failures, while in other contexts I want to handle the cleanup?) What's the best way to handle this? Btw. I'm doing this on OSX, I haven't tested whether this behaviour is different on Linux.

我觉得这非常违反直觉(也不是我想要的 - 如果在某些情况下我想使用该函数而不屏蔽故障,而在其他情况下我想处理清理呢?)处理这个问题的最佳方法是什么? ? 顺便提一句。我在 OSX 上这样做,我还没有测试过这种行为在 Linux 上是否不同。

回答by Martin Tournoij

Shell functions don't really have "return values", just exit codes.

Shell 函数并没有真正的“返回值”,只有退出代码。

You could add && :to the caller, this makes the command "tested", and won't exit it:

您可以添加&& :到调用者,这会使命令“经过测试”,并且不会退出:

foo() {
    echo 'x'
    return 42
}

out=$(foo && :)
echo $out

The :is the "null command" (ie. it doesn't do anything). In this case it doesn't even get executed, since it only gets run if fooreturn 0 (which it doesn't).

:是“空命令”(即它不做任何事情)。在这种情况下,它甚至不会被执行,因为它只有在foo返回 0 时才会运行(它没有)。

This outputs:

这输出:

x

It's arguably a bit ugly, but then again, all of shell scripting is arguably a bit ugly ;-)

可以说它有点难看,但话说回来,所有的 shell 脚本都可以说有点难看 ;-)

Quoting sh(1)from FreeBSD, which explains this better than bash's man page:

引用sh(1)FreeBSD,它比 bash 的手册页更好地解释了这一点:

 -e errexit
         Exit immediately if any untested command fails in non-interactive
         mode.  The exit status of a command is considered to be explicitly
         tested if the command is part of the list used to control an if,
         elif, while, or until; if the command is the left hand operand of
         an “&&” or “||” operator; or if the command is a pipeline preceded
         by the ! operator.  If a shell function is executed and its exit
         status is explicitly tested, all commands of the function are con‐
         sidered to be tested as well.