Bash函数忽略set -e

时间:2018-06-10 15:40:51

标签: linux bash

如何将一个函数作为一个"测试命令"并在失败时执行操作,同时在发生错误时仍然中止该功能? 请考虑以下脚本

#!/bin/bash -e

function foo() {
   echo Entering foo
   false
   echo Should not reach this line
}

foo || echo I want to see this line on failure in foo
foo

我得到的输出是

Entering foo
Should not reach this line
Entering foo

虽然我想得到

Entering foo
I want to see this line on failure in foo
Entering foo

我想我正在寻找的是一种将该功能标记为未经测试的命令的方法。根据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.

修改 预期的产出是错误的。编辑它是为了清晰

2 个答案:

答案 0 :(得分:2)

set -efoo的第一次通话中被停用,因为它位于||的左侧。

此外,您永远不会看到I want to see this ...字符串被输出,除非echo中的最后foo以某种方式失败(这是echo中的最后foo确定函数的退出状态。)

foo() {
    echo Entering foo
    false && echo Should not reach this line
}

foo || echo I want to see this line on failure in foo
foo

以上输出(有或没有set -x

Entering foo
I want to see this line on failure in foo
Entering foo

现在falsefoo中最后执行的语句。

答案 1 :(得分:0)

我最终将代码包装在下面的实用程序函数中。

#!/bin/bash -e

# Runs given code aborting on first error and taking desired action on failure
# $1 code to invoke, can be expression or function name
# $2 error handling code, can be function name or expressions
function saferun {
  set +e
  (set -E ; trap 'exit 1' ERR ; eval $1) 
  [ $? -ne 0 ] && eval $2
  set -e
}

function foo() {
   echo Entering foo
   false
   echo Should not reach this line
}

saferun foo "echo I want to see this line on failure in foo"
foo

让我们分解一下:

  • set +eset -e用于抑制错误失败,否则脚本将在第一次出错时退出
  • trap用于中止执行任何错误(而不是set -e()用于在子shell中运行给定代码,因此外部脚本将在失败后继续运行,并且set -E用于将陷阱传递到子shell中。所以(set -E ; trap 'exit 1' ERR ; eval $1)运行给定的代码/函数在第一次错误时中止而不退出整个脚本
  • $? -ne 0检查失败,eval $2运行错误处理代码