3be16713f9b27546cef83e7edbd2802dc13cd0e3
2 # Copyright (C) 2019 Ian Kelling
3 # SPDX-License-Identifier: GPL-3.0-or-later
5 # Commentary: Bash stack trace and error handling functions. This file
6 # is meant to be sourced. It loads some functions which you may want to
7 # call manually (see the comments at the start of each one), and then
8 # runs err-catch. See the README file for a slightly longer explanation.
11 #######################################
14 # usage: err-bash-trace [MESSAGE]
16 # This function is called by the other functions which print stack
19 # It does not show function args unless you first run:
21 # which err-catch & err-print do for you.
23 # MESSAGE Message to print just before the stack trace.
25 # _frame_start Optional variable to set before calling. The frame to
26 # start printing on. default=1. Useful when printing from
27 # an ERR trap function to avoid printing that function.
28 #######################################
30 local -i argc_index
=0 frame i start
=${_frame_start:-1}
35 for ((frame
=0; frame
< ${#FUNCNAME[@]}; frame
++)); do
36 argc
=${BASH_ARGC[frame]}
38 ((frame
< start
)) && continue
39 if (( ${#BASH_SOURCE[@]} > 1 )); then
40 source="${BASH_SOURCE[frame]}:${BASH_LINENO[frame-1]}:"
42 printf " from %sin \`%s" "$source" "${FUNCNAME[frame]}"
43 if shopt extdebug
>/dev
/null
; then
44 for ((i
=argc_index-1
; i
>= argc_index-argc
; i--
)); do
45 printf " %s" "${BASH_ARGV[i]}"
53 #######################################
54 # On error print stack trace and exit
57 # errcatch-cleanup If set, this command will run just before exiting.
58 #######################################
61 # This condition avoids starting the bash debugger in the case that
62 # this is sourced from a startup file, and you use a login shell to
63 # run a command. Avoid doing that if you want function arguments in
65 if [[ $
- != *c
* ]] && ! shopt login_shell
>/dev
/null
; then
72 local msg
="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
73 if (( ${#FUNCNAME[@]} > 2 )); then
79 set -e # err trap does not work within an error trap
80 if type -t errcatch-cleanup
>/dev
/null
; then
83 echo "$0: exiting with status $err"
91 #######################################
92 # For interactive shells: on error, print stack trace and return
95 # err_catch_ignore Array containing glob patterns to test against filenames to ignore
96 # errors from. Initialized to ignore bash-completion scripts on debian
98 # _err_func_last Used internally.
99 # _err_catch_err Used internally.
100 # _err_catch_i Used internally.
101 # _err_catch_ignore Used internally.
103 # misc: All shellcheck disables for this function are false positives.
104 #######################################
105 # shellcheck disable=SC2120
106 err-catch-interactive
() {
108 '/etc/bash_completion.d/*'
110 # shellcheck disable=SC2034
111 declare -i _err_func_last
=0
112 set -E; shopt -s extdebug
113 # shellcheck disable=SC2154
114 trap '_err_catch_err=$? _trap_bc="$BASH_COMMAND"
115 _err_catch_ignore=false
116 for _err_catch_i in "${err_catch_ignore[@]}"; do
117 if [[ ${BASH_SOURCE[0]} == $_err_catch_i ]]; then
118 _err_catch_ignore=true
122 if ! $_err_catch_ignore; then
123 if (( ${#FUNCNAME[@]} > _err_func_last )); then
124 echo ERR: \`$_trap_bc'"\'"' returned $_err_catch_err
126 _err_func_last=${#FUNCNAME[@]}
127 if (( _err_func_last )); then
128 printf " from %s:%s:in \`%s" "${BASH_SOURCE[0]}" "$(declare -F "${FUNCNAME[0]}"|awk "{print \$2}")" "${FUNCNAME[0]}"
129 if shopt extdebug >/dev/null; then
130 for ((_err_catch_i=${BASH_ARGC[0]}-1; _err_catch_i >= 0; _err_catch_i--)); do
131 printf " %s" "${BASH_ARGV[_err_catch_i]}"
135 return $_err_catch_err
142 #######################################
143 # Undoes err-catch/err-catch-interactive
144 #######################################
151 #######################################
152 # On error, print stack trace
153 #######################################
155 # help: on errors: print stack trace
157 # This function depends on err-bash-trace.
159 set -E; shopt -s extdebug
164 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
172 #######################################
173 # Print stack trace and exit
175 # Use this instead of the exit command to be more informative.
177 # usage: err-exit [EXIT_CODE] [MESSAGE]
179 # EXIT_CODE Default is 1.
180 # MESSAGE Print MESSAGE to stderr. If only one of EXIT_CODE
181 # and MESSAGE is given, we consider it to be an
182 # exit code if it is a number.
183 #######################################
188 if [[ ${1/[^0-9]/} == "$1" ]]; then
191 printf '%s\n' "$2" >&2
194 printf '%s\n' "$0: $1" >&2
197 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}"
199 echo "$0: exiting with code $code"
203 # We want this more often than not, so run it now.
204 if [[ $
- == *i
* ]]; then
205 err-catch-interactive