Is there a way to have a function in my bash script auto run on any command error?

You can use bash trap ERR to make your script quit if any command returns status greater than zero and execute your function on exiting.

Something like:

myfunc() {
  echo 'Error raised. Exiting!'
}

trap 'myfunc' ERR

# file does not exist, causing error
ls asd
echo 123

Note that bash trap ERR does implicit set -o errexit or set -e and is not POSIX.

And the ERR trap is not executed if the failed command is part of the command list immediately following until or while keyword, part of the test following the if or elif reserved words, part of a command executed in && or || list, or if the command’s return status is being inverted using !.


A (perhaps) simpler variation on the accepted answer:

  1. Use set -e to cause the failure of one command to abort the execution of a list.
  2. Simply list your commands.
  3. Use an if-then-else statement to execute your error-handling command(s).  This last piece is a bit tricky.  Watch:
set -e
if
    cmd1                        # e.g.,     cd foo
    cmd2                        # e.g.,     rm a
    cmd3                        # e.g.,     cd bar
    cmd4                        # e.g.,     rm b
then
    set +e
    commands to do upon success (if any)
else
    set +e
    myfunc
    other commands to do upon failure (if any)
fi

The tricky part is that you put your commands into the if part of the if-then-else, not the then part or the else part.  Recall that the syntax of the if statement is

if list; then list; [ elif list; then list; ] ... [ else list; ] fi
   ↑↑↑↑
The set -e tells the shell that, if cmd1 (cd foo) fails, it should not go on and execute cmd2 (rm a), and so on down the line.  If this happened to a command at the outermost level of a shell script, the shell would exit.  However, since the cmd1 · cmd2 · cmd3 · cmd4 is a (compound) list following an if, the failure of any of those four commands simply causes the entire list to fail — which causes the else clause to be executed.  If all four commands succeed, the then clause is executed.

In either case, the first thing you should do is probably to disable (turn off) the e option by doing set +e. Otherwise, the script might get blown out of the water if a command in myfunc fails.

set -e is specified and described in the POSIX specification.