Bash Error Handler

01 Jan 2022 - nicolas

Our bash scripts can exit in multiple ways, each one having its own status.

We can define a function to be executed on specific exit status, for instance if your script exit as planned or if an error occured:

trap myCommandToExecute myExitStatusHere
trap myCommandToExecute oneExitStatusHere anotherExitStatusHere yetAnotherExitStatusHere

Be aware that a failed command inside a function will cause our script to exit with an exit status and not an err status, so either we specify in our function how to handle your errors:

#! /bin/bash

functionCallingCommandWithError() {
    trap _handleExit err # we need to specify again how to handle errors
    ls unknownFile # will break this method and be trapped by 'exit' instead of 'err'
    echo "hello world!"
}

_handleExit() {
    echo "an error occured"
}

trap _handleExit err

functionCallingCommandWithError

Or we use both err and exit like so:

#! /bin/bash

functionCallingCommandWithError() {
    ls unknownFile # will break this method and be trapped by 'exit' instead of 'err'
    echo "hello world!"
}

_handleExit() {
    echo "an error occured"
}

trap _handleExit err exit # this time _handleExit can be called twice in case of an error

functionCallingCommandWithError

And here is what I like to do:

#! /bin/bash

hasHandleExitBeenCalled=0

functionCallingCommandWithError() {
    ls unknownFile # will break this method and be trapped by 'exit' instead of 'err'
    echo "hello world!"
}

brokenFunction() {
    echo ${FUNCNAME[0]}

    return 3 # will be trapped by 'err'
}

_handleExit() {
    # remember last exit code has the next 'if' statement will override it
    lastExitCode=$?

    # avoid _handleExit to be called more than once in case of brokenFunction
    if [ 1 -eq $hasHandleExitBeenCalled ]
    then
        return
    fi

    if [ $lastExitCode -eq 3 ]; then
        echo "brokenFunction has been called."
    fi
    echo "an error occured"

    hasHandleExitBeenCalled=1
}

trap _handleExit err exit # 'exit' is mandatory to avoid calling _handleExit twice in case of a direct error like in brokenFunction

"$@" # I like to use this when using my scripts, so I can call 'myScriptName myFunctionName'. You can replace this line by a function name if you prefer.