2 # Copyright 2018 Ian Kelling
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
8 # http://www.apache.org/licenses/LICENSE-2.0
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
17 # Commentary: Bash stack trace and error handling functions. This file
18 # is meant to be sourced. It loads some functions which you may want to
19 # call manually (see the comments at the start of each one), and then
20 # runs err-catch. See the README file for a slightly longer explanation.
23 #######################################
26 # usage: err-bash-trace [MESSAGE]
28 # This function is called by the other functions which print stack
31 # It does not show function args unless you first run:
33 # which err-catch & err-print do for you.
35 # MESSAGE Message to print just before the stack trace.
37 # _frame_start Optional variable to set before calling. The frame to
38 # start printing on. default=1. Useful when printing from
39 # an ERR trap function to avoid printing that function.
40 #######################################
42 local -i argc_index
=0 frame i start
=${_frame_start:-1}
47 for ((frame
=0; frame
< ${#FUNCNAME[@]}; frame
++)); do
48 argc
=${BASH_ARGC[frame]}
50 ((frame
< start
)) && continue
51 if (( ${#BASH_SOURCE[@]} > 1 )); then
52 source="${BASH_SOURCE[frame]}:${BASH_LINENO[frame-1]}:"
54 printf " from %sin \`%s" "$source" "${FUNCNAME[frame]}"
55 if shopt extdebug
>/dev
/null
; then
56 for ((i
=argc_index-1
; i
>= argc_index-argc
; i--
)); do
57 printf " %s" "${BASH_ARGV[i]}"
65 #######################################
66 # On error print stack trace and exit
69 # ${_errcatch_cleanup[@]} Optional command & args that will run before exiting
70 #######################################
72 set -E; shopt -s extdebug
77 local msg
="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
78 if (( ${#FUNCNAME[@]} > 2 )); then
84 set -e # err trap does not work within an error trap
85 # note :-: makes this compatible with set -u, assigns : if unset, but shellcheck
86 # doesn't understand that.
87 # shellcheck disable=SC2154
88 "${_errcatch_cleanup[@]:-:}"
89 echo "$0: exiting with status $err"
97 #######################################
98 # For interactive shells: on error, print stack trace and return
101 # err_catch_ignore Array containing glob patterns to test against filenames to ignore
102 # errors from. Initialized to ignore bash-completion scripts on debian
104 # _err_func_last Used internally.
105 # _err_catch_err Used internally.
106 # _err_catch_i Used internally.
107 # _err_catch_ignore Used internally.
109 # misc: All shellcheck disables for this function are false positives.
110 #######################################
111 # shellcheck disable=SC2120
112 err-catch-interactive
() {
114 '/etc/bash_completion.d/*'
116 # shellcheck disable=SC2034
117 declare -i _err_func_last
=0
118 set -E; shopt -s extdebug
119 # shellcheck disable=SC2154
120 trap '_err_catch_err=$? _trap_bc="$BASH_COMMAND"
121 _err_catch_ignore=false
122 for _err_catch_i in "${err_catch_ignore[@]}"; do
123 if [[ ${BASH_SOURCE[0]} == $_err_catch_i ]]; then
124 _err_catch_ignore=true
128 if ! $_err_catch_ignore; then
129 if (( ${#FUNCNAME[@]} > _err_func_last )); then
130 echo ERR: \`$_trap_bc'"\'"' returned $_err_catch_err
132 _err_func_last=${#FUNCNAME[@]}
133 if (( _err_func_last )); then
134 printf " from %s:%s:in \`%s" "${BASH_SOURCE[0]}" "$(declare -F "${FUNCNAME[0]}"|awk "{print \$2}")" "${FUNCNAME[0]}"
135 if shopt extdebug >/dev/null; then
136 for ((_err_catch_i=${BASH_ARGC[0]}-1; _err_catch_i >= 0; _err_catch_i--)); do
137 printf " %s" "${BASH_ARGV[_err_catch_i]}"
141 return $_err_catch_err
148 #######################################
149 # Undoes err-catch/err-catch-interactive
150 #######################################
157 #######################################
158 # On error, print stack trace
159 #######################################
161 # help: on errors: print stack trace
163 # This function depends on err-bash-trace.
165 set -E; shopt -s extdebug
170 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err"
178 #######################################
179 # Print stack trace and exit
181 # Use this instead of the exit command to be more informative.
183 # usage: err-exit [EXIT_CODE] [MESSAGE]
185 # EXIT_CODE Default is 1.
186 # MESSAGE Print MESSAGE to stderr. If only one of EXIT_CODE
187 # and MESSAGE is given, we consider it to be an
188 # exit code if it is a number.
189 #######################################
194 if [[ ${1/[^0-9]/} == "$1" ]]; then
197 printf '%s\n' "$2" >&2
200 printf '%s\n' "$0: $1" >&2
203 echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}"
205 echo "$0: exiting with code $code"
209 # We want this more often than not, so run it now.
210 if [[ $
- == *i
* ]]; then
211 err-catch-interactive