Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Bash: Exit and cleanup on error

In my Bash scripts, I would like to make sure that the script exits as soon as there is an error. (E.g., to avoid a mistaken rm -f * after a failed cd some_directory.) For this reason, I always use the -e flag for bash.

Now, I would also like to execute some cleanup code in some of my scripts. From this blog post I gathered

#!/bin/bash

cd invalid_directory
echo ':('

function clean_up {
  echo "> clean_up"
  exit 0
}
trap clean_up EXIT

The output I get is

./test.sh: line 3: cd: invalid_directory: No such file or directory
:(
> clean_up

so it does what's advertised. However, when using -e for bash, I'm only getting

./test.sh: line 3: cd: invalid_directory: No such file or directory

so the script exits without calling clean_up.

How can I have a bash script exit at all errors and call a clean up script every time?

like image 756
Nico Schlömer Avatar asked Mar 31 '16 13:03

Nico Schlömer


People also ask

Does a bash script exit on error?

Bash provides a command to exit a script if errors occur, the exit command. The argument N (exit status) can be passed to the exit command to indicate if a script is executed successfully (N = 0) or unsuccessfully (N != 0).

What is $@ in bash?

bash [filename] runs the commands saved in a file. $@ refers to all of a shell script's command-line arguments. $1 , $2 , etc., refer to the first command-line argument, the second command-line argument, etc. Place variables in quotes if the values might have spaces in them.

What is Pipefail in bash?

pipefail. If set, the return value of a pipeline is the value of the last (rightmost) command to exit with a non-zero status, or zero if all commands in the pipeline exit successfully. This option is disabled by default.

How do you throw a bash script error?

Using the set -e Option. Bash has this built-in set command to set different options in the shell. One of the many options is errexit. Merely setting this option helps us exit the script when any of the commands return a non-zero status.


1 Answers

You are never reaching the trap command; your shell exits before the trap is configured.

set -e
clean_up () {
    ARG=$?
    echo "> clean_up"
    exit $ARG
} 
trap clean_up EXIT
cd invalid_directory
echo "Shouldn't reach this"

However, it's better to do your own error handling. You often want to vary your behavior depending on the exact reason why your script is exiting, something that is more complicated to do if you are running a single handler for all exits (even if you restrict your trap to ERR instead of EXIT).

cd invalid_directory || { echo "cd to invalid_directory failed" >&2; exit 1; }
echo "Shouldn't reach this"

This doesn't mean you have to abandon your clean_up function. It will still be executed for explicit exits, but it should be restricted to code that should run no matter why your script exits. You can also put a trap on ERR to execute code that should only be executed if you script is exiting with a non-zero exit status.

like image 127
chepner Avatar answered Oct 20 '22 16:10

chepner