Erez Gedalyahu
Erez Gedalyahu

Reputation: 41

How to fail a bash script when while/if/etc has errors?

I run a Jenkins pipeline job with Groovy. The Groovy calls bash scripts for each step.

I want to fail the whole job when something in the way has errors.

For Groovy I use the returnStatus: true.

For Bash I use set -e.

But a bash script with set -e, does not exit if, for example, a while statement has errors. This is what should actually happen, according to the Linux manual page for 'set'. I would like to know how to exit immediately in that scenario.

The script:

[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"

Let's say 'commands.txt' doesn't exist. Running script:

[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

Although the while statement returns exit code 1, the script continues and ends successfully, as checked right after, with echo $?.

This is how I force the Groovy to fail, after a step with bash/python/etc command/script returns a none-zero exit code:

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

First question, how can I make the SHELL script to fail when the while/if/etc statements have errors? I know I can use command || exit 1 but it doesn't seem elegant if I have dozens of statements like this in the script.

Second question, is my Groovy error handling correct? Can anyone suggest an event better way? Or maybe there is a Jenkins plugin/official way to do so?

Upvotes: 4

Views: 2999

Answers (4)

mcoolive
mcoolive

Reputation: 4205

About the Bash script.

Your issue is that the fail redirection does not abort the bash script, despite the use of set -e. I was surprised my-self. But it's my first disappointment about set -e, so now I consider to not trust it and I abuse of stuff like $command || exit 1 ...

Here you can do the following:

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

But the whole loop should be simplified into:

bash $FILE

Upvotes: 1

W4nn4Die
W4nn4Die

Reputation: 11

[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"

When yor perform a echo $? after this script it will always be 0, because the last command was echo "echos after faulty while" you can ad an exit 1 at the end of your script. In exit 1 the number 1 will be the error code, you can use other. So the script will be

[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

Upvotes: 0

niri9428480
niri9428480

Reputation: 425

First question this link may be helpful Aborting a shell script if any command returns a non-zero value

Second question: You can improve your error handling using try and catch for exception handling.

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

Upvotes: 1

Yannoff
Yannoff

Reputation: 374

Why don't you just use the while exit code and return it? (See this modified version of your script, the last lines)

[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

Upvotes: 0

Related Questions