【问题标题】:How to fail a bash script when while/if/etc has errors?当 while/if/etc 出现错误时如何使 bash 脚本失败?
【发布时间】:2019-07-04 10:43:49
【问题描述】:

我使用 Groovy 运行 Jenkins 管道作业。 Groovy 为每个步骤调用 bash 脚本。

当出现问题时,我想让整个工作失败。

对于 Groovy,我使用 returnStatus: true

对于 Bash,我使用 set -e

但是,如果 while 语句有错误,则带有 set -e 的 bash 脚本不会退出。根据“set”的 Linux 手册页,这实际上应该发生。 我想知道在那种情况下如何立即退出。

脚本:

[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash

set -xe

FILE=commands.txt

echo "echos before while"

# Run the commands in the commands file
while read COMMAND
do
    $COMMAND
done < $FILE
echo $?

echo "echos after faulty while"

假设“commands.txt”不存在。 运行脚本:

[jenkins-user@jenkins ~]$ sh script.sh
echos before while
script.sh: line 13: commands.txt: No such file or directory
1
echos after faulty while
[jenkins-user@jenkins ~]$ echo $?
0

虽然 while 语句返回退出代码 1,但脚本继续并成功结束,正如之后检查的那样,echo $?

这就是我强制 Groovy 失败的方式,在使用 bash/python/etc 命令/脚本的步骤返回非零退出代码之后:

pipeline {
    agent any
    stages {
        stage("A") {
            steps {
                script {
                    def rc = sh(script: "sh A.sh", returnStatus: true)
                    if (rc != 0)  {
                        error "Failed, exiting now..."
                    }
                }
            }
        }
    }
}

第一个问题,当 while/if/etc 语句有错误时,如何使 SHELL 脚本失败?我知道我可以使用command || exit 1,但如果我在脚本中有几十个这样的语句,它似乎并不优雅。

第二个问题,我的 Groovy 错误处理是否正确?任何人都可以提出更好的活动方式吗?或者也许有一个 Jenkins 插件/官方方法可以做到这一点?

【问题讨论】:

  • 有点晚了,但是你有没有解决这个问题,即自动检测到 bash 内置错误?感谢您让我知道 '-e' 没有涵盖 'while'。在使用它之前进行防御性编码的另一个原因,即[[ -f $FILE ]]

标签: linux bash shell jenkins groovy


【解决方案1】:

第一个问题这个链接可能会有所帮助Aborting a shell script if any command returns a non-zero value

第二个问题:您可以使用 try 和 catch 进行异常处理来改进错误处理。

 try{
       def rc = sh(script: "sh A.sh", returnStatus: true)
       if (rc != 0)  {
                error "Failed, exiting now..."
       }
    }  
    catch (Exception er){
         errorMessage = er.getMessage();
    }

【讨论】:

  • 你能解释一下为什么要在上面添加 try/catch 吗?
  • 不要在顶部添加 try/catch 在你的阶段块中添加 try/catch。 Try/catch 有助于将错误处理与常规代码分开。
【解决方案2】:

关于 Bash 脚本。

您的问题是失败重定向不会中止 bash 脚本,尽管使用了 set -e。我很惊讶自己。但这是我对set -e 的第一次失望,所以现在我考虑不相信它,我滥用$command || exit 1 之类的东西......

在这里您可以执行以下操作:

set -xe -o pipefail
cat $FILE | while read command; do $command ; done

但是整个循环应该简化成:

bash $FILE

【讨论】:

  • 为了清楚起见(以及像我这样粗心的读者):在原始问题中添加 -o pipefail 不会改变其行为。需要把它变成管道。
【解决方案3】:

为什么不直接使用while 退出代码并返回它? (请参阅此修改后的脚本版本,最后几行)

[jenkins-user@jenkins ~]$ cat script.sh
#!/bin/bash

set -xe

FILE=commands.txt

echo "echos before while"

# Run the commands in the commands file
while read COMMAND
do
    $COMMAND
done < $FILE
status=$?

echo "echos after faulty while"

exit $status

【讨论】:

    【解决方案4】:
    [jenkins-user@jenkins ~]$ cat script.sh
    #!/bin/bash
    
    set -xe
    
    FILE=commands.txt
    
    echo "echos before while"
    
    # Run the commands in the commands file
    while read COMMAND
    do
        $COMMAND
    done < $FILE
    echo $?
    
    echo "echos after faulty while"
    

    当您在此脚本之后执行echo $? 时,它将始终为0,因为最后一个命令是echo "echos after faulty while",您可以在脚本末尾添加exit 1。在exit 1 中,数字 1 将是错误代码,您可以使用其他。所以脚本将是

    [jenkins-user@jenkins ~]$ cat script.sh
    #!/bin/bash
    
    set -xe
    
    FILE=commands.txt
    
    echo "echos before while"
    
    # Run the commands in the commands file
    while read COMMAND
    do
        $COMMAND
    done < $FILE
    echo $?
    exit 1
    

    【讨论】:

    • 我认为发帖人的意思是它不应该到达echo "echos after faulty while" 行,因为他们在顶部有一个set -xe;当while循环失败时它应该退出。
    猜你喜欢
    • 1970-01-01
    • 2016-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-21
    • 2020-06-11
    • 1970-01-01
    • 2020-11-04
    相关资源
    最近更新 更多