Search code examples
bashshellshexit

Exiting a shell-script at the end with a non-zero code if any command fails


I am making a shell script that runs a bunch of tests as part of a CI pipeline. I would like to run all of the tests (I DO NOT WANT TO EXIT EARLY if one test fails). Then, at the end of the script, I would like to return with a negative exit code if any of the tests failed.

Any help would be appreciated. I feel like this would be a very common use case, but I wasn't able to find a solution with a bit of research. I am pretty sure that I don't want set -e, since this exits early.

My current idea is to create a flag to keep track of any failed tests:

flag=0
pytest -s || flag=1
go test -v ./... || flag=1
exit $flag

This seems strange, and like more work than necessary, but I am new to bash scripts. Am I missing something?


Solution

  • One possible way would be to catch the non-zero exit code via trap with ERR. Assuming your tests don't contain pipelines | and just return the error code straight to the shell launched, you could do

    #!/usr/bin/env bash
    
    exitCodeArray=()
    
    onFailure() {
        exitCodeArray+=( "$?" )
    }
    
    trap onFailure ERR
    
    # Add all your tests here
    
    addNumbers () {
        local IFS='+'
        printf "%s" "$(( $* ))"
    }
    

    Add your tests anywhere after the above snippet. So we keep adding the exit code to the array whenever a test returns a non-zero return code. So for the final assertion we check if the sum of the array elements is 0, because in an ideal case all cases should return that if it is successful. We reset the trap set before

    trap '' ERR
    
    if (( $(addNumbers "${exitCodeArray[@]}") )); then
        printf 'some of your tests failed\n' >&2
        exit -1
    fi