Bash – How to catch and handle nonzero exit status within a Bash function

basherror handlingexitfunctionshell-script

Say I have the following (pointless) Bash function:

myfunc() {
    ls
    failfailfail
    uptime
}

I run it as follows:

myfunc || echo "Something is wrong."

What I want to happen is ls runs (as it should), failfailfail does not work (since it doesn't exist), and uptime doesn't run. The return value of the function would be nonzero, and the error message would be shown. The return value doesn't have to be the exact exit status of the failed command, it just shouldn't be zero.

What actually happens is I get the output of ls, followed by "-bash: failfailfail: command not found", followed by the output of uptime. The error message is not shown, because the failed exit status is getting eaten.

set -e has no useful effect, either within the function or in the scope where the function is called. The only way I can get this to work the way I want is:

myfunc() {
    ls || return $?
    failfailfail || return $?
    uptime || return $?
}

But this seems awfully repetitive and ugly. Is there another way to clean this up?

Best Answer

Under set -e, the non-existence of failfailfail causes the whole script to exit (or the subshell, if the function is executed in a subshell).

If you don't need to modify the shell state from the function, you can run it in a subshell.

myfunc() (
    set -e
    ls
    failfailfail
    uptime
)

Another approach in bash is to set an ERR trap to execute return. If you want to make it a local setting, you need to restore the old trap value, which is a little cumbersome.

myfunc() {
    local old_ERR_trap=$(trap -p ERR)
    if [[ -z $old_ERR_trap ]]; then old_ERR_trap="trap - ERR"; fi
    trap 'local ret=$?; eval "$old_ERR_trap"; return $ret' ERR
    ls
    failfailfail
    uptime
}
Related Question