Bash - 如果语句之一 return 错误代码 != 0,则中断条件子句

Bash - break conditional clause if one of the statements return error code != 0

我有以下 bash 脚本,它 运行 在我的 CI 上并且打算 运行 我的代码在物理 MacOS 和几个 docker Linux 图片:

if [[ "$OS_NAME" == "mac_os" ]]; then
       make all;
       run_test1;
       run_test2;
       make install;
    else
       docker exec -i my_docker_image bash -c "make all";
       docker exec -i my_docker_image bash -c "run_test1";
       docker exec -i my_docker_image bash -c "run_test2"; 
       docker exec -i my_docker_image bash -c "make install";
    fi

如果测试失败(run_test1run_test2)他们 return 错误代码 1。如果他们通过他们 return 错误代码 0。

整个脚本 运行 具有 set -e,所以只要它看到 0 以外的退出代码,它就会停止并导致整个构建失败。

当前的问题是,当 run_test1run_test2 位于条件子句内时 - 当它们失败并且 return 错误代码 1 时,条件子句不会中断并且尽管测试未通过,但构建成功。

所以我有两个问题:

您的代码应该按预期工作,让我们演示一下:

#!/usr/bin/env bash

set -e  

var="test"   
if [[ $var = test ]]; then
    echo "Hello"
    cat non_existing_file &> /dev/null
    echo "World"
else
    echo "Else hello"
    cat non_existing file &> /dev/null
fi 

echo I am done

这将按预期仅输出 "Hello"。如果它对您的工作方式不同,则意味着您没有提供足够的代码。让我们尝试更改上面的代码并在 set -e 被忽略时显示一些示例,就像您的情况一样:

引用 Bash Reference manual

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.

现在让我们引用相同的手册,看看忽略-e的一些情况:

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 in an if statement, 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 status is being inverted with !.

从这里我们可以看出,例如,如果您在一个函数中有上面的代码并使用 if 测试该函数,set -e 将被忽略:

#!/usr/bin/env bash

set -e  

f() {
   var="test"
   if [[ $var = test ]]; then
       echo "Hello"
       cat non_existing_file &> /dev/null
       echo "World"
   else
       echo "Else hello"
       cat non_existing file &> /dev/null
   fi
}

if f; then echo "Function OK!"; fi

echo I am done

函数 f 在忽略 set -e 的上下文中执行(if 语句),这意味着 set -e 不会影响在此函数中执行的任何命令。此代码输出:

Hello

World

Function OK!

I am done

当您在 && 或 || 中执行函数时,同样的规则适用列表。如果将行 if f; then echo "Function OK!"; fi 更改为 f && echo "Function OK",您将获得相同的输出。我相信后者可能是你的情况。

即便如此,您的 第二个问题 可以通过添加 || exit:

轻松解决
run_test1 || exit 1;
run_test2 || exit 1;

你的第一个问题是微不足道的,例如,如果你在一个函数中。然后你可以简单地return。或者在一个循环里面,那么你可以break。如果你不是,打破条件条款就没那么容易了。看看这个.

set -e 可能是一件令人惊讶的事情,因为它在许多情况下都被忽略了。请谨慎使用并注意这些情况。