I'm working on a bash script and as I've been going I've learned about traps, signals, function return codes and other such features I've not previously used.
I may be thinking about things incorrectly - I'm looking for some advice.
I am setting the following options:
set -o errexit
set -o nounset
set -o noclobber
I've got the following exit and err traps in my bash script:
# Error handler. This function is called anytime an ERR signal is received.
# This function should never be explictly called.
function _trap_error () {
if [ ! -v _VERBOSE ]; then
echo "An error has occurred. Exiting."
else
_name="$0" # name of the script
_lastline="$1" # argument 1: last line of error occurence
_lasterr="$2" # argument 2: error code of last command
echo "${_name}: line ${_lastline}: exit status of last command: ${_lasterr}"
exit 1
fi
}
trap '_trap_error ${LINENO} ${$?}' ERR
# Exit handler. This function is called anytime an EXIT signal is received.
# This function should never be explicitly called.
function _trap_exit () {
[ -v _POPD ] && popd &> /dev/null
}
trap _trap_exit EXIT
They work much as I'd expect. Rather than inserting error checking into all my functions, I'm attempting to leverage the traps to handle this for me, for example when checking for the existence of a file. If the specified module can't be loaded, I'd like to catch it as an error, display an error message, and exit.
function _module_path () {
echo "mod.d/$2s/$1/__init__.sh"
}
function _module_exists () {
[ -f $(_module_path $1 $2) ] && return 0 || return 1
}
function _module_push () {
_module_exists $1 $2 && _MODULES+=$( _module_path $1 $2 ) || msg "Module $1 does not exist."
}
However, setting the return code to 0 in conjunction with errexit triggers an EXIT signal, which is caught by my exit trap instead. I started trying to figure out if I can manually emit an ERR signal instead, but haven't found an answer and started to wonder if I'm going about this correctly.
[ -v ]
. I think its the best answer I've ever written. Also, what is${$?}
? I suspect it's your problem. That should be an invalid substitution as far as I can tell. http://unix.stackexchange.com/a/120008/52934 – mikeserv Apr 20 '14 at 01:21info bash
: TheERR
trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a command executed in a&&
or||
list, or if the command's return value is being inverted via!
. – devnull Apr 20 '14 at 02:55${unset_var?this is written to stderr}
or justfalse
– mikeserv Apr 20 '14 at 03:05echo ${$?}
works, butn=$? ; echo ${$n}
returns a bad substitution error. See what i mean? Don't know why youre putting${}
around it. Please see that other post - it discusses all kinds of ways of generating, handling errors. – mikeserv Apr 20 '14 at 16:13exit 0
, then that runs the EXIT trap, that's what the EXIT trap is all about, so how is that surprising? Please give an example of a behavior that you observe (with a complete script to reproduce it), and explain what different behavior you want to obtain. – Gilles 'SO- stop being evil' Apr 20 '14 at 22:48${unset?}
. Sotest_var=${?%%*[1-9]} ; ${test_var?failed test, trap triggered}
might be useful. Or,more simply,_fn || handle_it
would fail for any exit code other than 0. If you want a central err handler your going to need a central launcher handler as well - probably best if theyre the same thing. – mikeserv Apr 21 '14 at 17:01${test_var:?...}
- sorry. I suppose you could justset -e
and the shell would then automatically fail any non-zero exit return code, but relying on a shell option to handle all exceptions that way is risky business - how can you be certain all called programs follow the zero return=success convention? – mikeserv Apr 25 '14 at 12:50echo ${$?}
works the same asecho $$
. – Wildcard Sep 06 '17 at 20:34