如果我使用“||”捕获复合命令的错误代码,set -e subshel​​l 不会在第一个失败的命令上退出

如果我使用“||”捕获复合命令的错误代码,set -e subshel​​l 不会在第一个失败的命令上退出

我有一个script.sh,我必须正确诊断其中的任何错误,因此prova如果出现错误,该函数不应中途停止,而应继续到最后报告其错误消息。为此,我必须使用 OR 运算符从子 shell 中捕获任何错误代码||,但这样做会导致子 shell 在第一个失败的命令时不会退出,而这不是我想要的。

例子:

假设我在包含脚本的目录中,从 shell 运行以下命令:

./script.sh

如果我不使用 OR||运算符,函数就不会继续执行到最后,因此不会产生错误消息:

#!/bin/bash -e
...
prova () {
    local function_name="${FUNCNAME[0]}"
    local exit_code=0
    (
        set -e
        prova1
        prova2
        prova3
    )
    echo "$function_name: An error has occurred." >&2
    return $exit_code
}
prova
...

标准错误:

./script.sh: line 7: prova1: command not found

如果我使用 OR||运算符,它会执行所有 3 个命令,但它仍应在第一个捕获其退出代码的命令处停止:

#!/bin/bash -e
...
prova () {
    local function_name="${FUNCNAME[0]}"
    local exit_code=0
    (
        set -e
        prova1
        prova2
        prova3
    ) || exit_code=$?
    if [[ $exit_code -ne 0 ]]; then
        echo "$function_name: An error has occurred." >&2
    fi
    return $exit_code
}
prova
...

标准错误:

./script.sh: line 7: prova1: command not found
./script.sh: line 8: prova2: command not found
./script.sh: line 9: prova3: command not found
prova: An error has occurred.

我想要这个 StdErr:

./script.sh: line 7: prova1: command not found
prova: An error has occurred.

我如何获得它?

答案1

因为复合命令是 || 列表的一部分,而不是该列表中的最后一个,-e所以选项在该复合命令中不起作用。请参阅set内置命令的文档bash 手册

-e    Exit  immediately  if  a  pipeline  (which  may  consist of a single simple
      command), a list, or a compound command (see SHELL  GRAMMAR  above),  exits
      with  a non-zero status.  The shell does not exit if the command that fails
      is part of the command list immediately following a while or until keyword,
      part  of  the  test  following  the  if or elif reserved words, part of any
      command executed in a && or || list except the command following the  final
      &&  or  ||,  any  command  in  a pipeline but the last, or if the command's
      return value is being inverted with !.  If a compound command other than  a
      subshell  returns  a  non-zero status because a command failed while -e was
      being ignored, the shell does not exit.  A trap on ERR, if set, is executed
      before  the  shell exits.  This option applies to the shell environment and
      each subshell environment separately  (see  COMMAND  EXECUTION  ENVIRONMENT
      above),  and  may cause subshells to exit before executing all the commands
      in the subshell.

      If a compound command or shell function executes in a context where  -e  is
      being ignored, none of the commands executed within the compound command or
      function body will be affected by the -e setting, even if -e is set  and  a
      command  returns a failure status.  If a compound command or shell function
      sets -e while executing in a context where -e is ignored, that setting will
      not  have  any  effect until the compound command or the command containing
      the function call completes.

要在第一个命令失败后退出子 shell,可以使用如下代码:

prova () {
    local exit_code=0
    (
        prova1 &&
        prova2 &&
        prova3
    ) || exit_code=$?
    return $exit_code
}

您甚至可能不需要在函数中使用子shell。

如果您需要-e在函数中使用复合命令,那么可以使用如下命令:

#!/bin/bash

prova() {
    (
    set -e
    prova1
    prova2
    prova3
    )
    
    local exit_code=$?
    if [[ $exit_code -ne 0 ]]; then
        echo "${FUNCNAME[0]}: An error has occurred." >&2
    fi
    return $exit_code
}

prova

相关内容