Skip to content

Instantly share code, notes, and snippets.

@ahendrix
Created October 17, 2013 18:56
Show Gist options
  • Star 56 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save ahendrix/7030300 to your computer and use it in GitHub Desktop.
Save ahendrix/7030300 to your computer and use it in GitHub Desktop.
bash stacktrace
function errexit() {
local err=$?
set +o xtrace
local code="${1:-1}"
echo "Error in ${BASH_SOURCE[1]}:${BASH_LINENO[0]}. '${BASH_COMMAND}' exited with status $err"
# Print out the stack trace described by $function_stack
if [ ${#FUNCNAME[@]} -gt 2 ]
then
echo "Call tree:"
for ((i=1;i<${#FUNCNAME[@]}-1;i++))
do
echo " $i: ${BASH_SOURCE[$i+1]}:${BASH_LINENO[$i]} ${FUNCNAME[$i]}(...)"
done
fi
echo "Exiting with status ${code}"
exit "${code}"
}
# trap ERR to provide an error handler whenever a command exits nonzero
# this is a more verbose version of set -o errexit
trap 'errexit' ERR
# setting errtrace allows our ERR trap handler to be propagated to functions,
# expansions and subshells
set -o errtrace
@moisei
Copy link

moisei commented Jul 24, 2022

On any error print full stack trace of the failure and exit with the original error code
https://gist.github.com/moisei/4cb326101eae1d9d07244cfd9ee2ef5a

@parke
Copy link

parke commented Oct 3, 2022

What is the purpose of line 4: local code="${1:-1}" ? It seems like $1 will never be set, so $code will always be simply 1.

@trainman419
Copy link

@parke it's been almost a decade since I wrote this, so my memory is a little fuzzy.

I think there might have been cases where I called the error handler directly instead of through the trap in a few places, particularly if I wanted a stack trace but didn't want my script to exit.

@parke
Copy link

parke commented Oct 6, 2022

@trainman419 I have discovered one reason you might want to receive codes via $1. Namely, so you can send multiple traps to the same handler, yet distinguish between them. For example:

trap  'errexit  ERR '  ERR
trap  'errexit  TERM'  TERM

Relatedly, you might want to do the following:

trap  'errexit   '  ERR
trap  'errexit  1'  TERM

The reason is that on ERR, $? will be non-zero. However on SIGTERM, $? will be zero. So if you want to exit with non-zero on a trap of SIGTERM, that non-zero value needs to come from somewhere other than $?.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment