What is your favorite method to handle errors in Bash? The best example of handling errors I have found on the web was written by William Shotts, Jr at http://www.linuxcommand.org.
He suggests using the following function for error handling in Bash:
#!/bin/bash
# A slicker error handling routine
# I put a variable in my scripts named PROGNAME which
# holds the name of the program being run. You can get this
# value from the first item on the command line ($0).
# Reference: This was copied from <http://www.linuxcommand.org/wss0150.php>
PROGNAME=$(basename $0)
function error_exit
{
# ----------------------------------------------------------------
# Function for exit due to fatal program error
# Accepts 1 argument:
# string containing descriptive error message
# ----------------------------------------------------------------
echo "${PROGNAME}: ${1:-"Unknown Error"}" 1>&2
exit 1
}
# Example call of the error_exit function. Note the inclusion
# of the LINENO environment variable. It contains the current
# line number.
echo "Example of error with line number and message"
error_exit "$LINENO: An error has occurred."
Do you have a better error handling routine that you use in Bash scripts?
Using trap is not always an option. For example, if you're writing some kind of re-usable function that needs error handling and that can be called from any script (after sourcing the file with helper functions), that function cannot assume anything about exit time of the outer script, which makes using traps very difficult. Another disadvantage of using traps is bad composability, as you risk overwriting previous trap that might be set earlier up in the caller chain.
There is a little trick that can be used to do proper error handling without traps. As you may already know from other answers,
set -e
doesn't work inside commands if you use||
operator after them, even if you run them in a subshell; e.g., this wouldn't work:But
||
operator is needed to prevent returning from the outer function before cleanup. The trick is to run the inner command in background, and then immediately wait for it. Thewait
builtin will return the exit code of the inner command, and now you're using||
afterwait
, not the inner function, soset -e
works properly inside the latter:Here is the generic function that builds upon this idea. It should work in all POSIX-compatible shells if you remove
local
keywords, i.e. replace alllocal x=y
with justx=y
:Example of usage:
Running the example:
The only thing that you need to be aware of when using this method is that all modifications of Shell variables done from the command you pass to
run
will not propagate to the calling function, because the command runs in a subshell.This trick is useful for missing commands or functions. The name of the missing function (or executable) will be passed in $_
I've used
before; i think because 'exit' was failing for me for some reason. The above defaults seem like a good idea, though.
This has served me well for a while now. It prints error or warning messages in red, one line per parameter, and allows an optional exit code.
Reading all the answers on this page inspired me a lot.
So, here's my hint:
file content: lib.trap.sh
Example of usage:
file content: trap-test.sh
Running:
Output:
As you can see from the screenshot below, the output is colored and the error message comes in the used language.
An equivalent alternative to "set -e" is
It makes the meaning of the flag somewhat clearer than just "-e".
Random addition: to temporarily disable the flag, and return to the default (of continuing execution regardless of exit codes), just use
This precludes proper error handling mentioned in other responses, but is quick & effective (just like bash).