From 5a600375360829c82bc2f51aa758d3c761d1203e Mon Sep 17 00:00:00 2001 From: Ian Kelling Date: Mon, 4 Nov 2019 15:58:02 -0500 Subject: [PATCH] use ruby style, support interactive shell --- err | 84 +++++++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 65 insertions(+), 19 deletions(-) diff --git a/err b/err index 73013a8..f6a7042 100644 --- a/err +++ b/err @@ -23,7 +23,7 @@ ####################################### # Print stack trace # -# usage: err-bash-trace [FRAME_START] +# usage: err-bash-trace [MESSAGE] # # This function is called by the other functions which print stack # traces. @@ -32,28 +32,27 @@ # shopt -s extdebug # which err-catch & err-print do for you. # -# FRAME_START The frame to start printing on. default=0. Useful when -# printing from an ERR trap function to avoid printing -# that function. +# MESSAGE Message to print just before the stack trace. +# +# _frame_start Optional variable to set before calling. The frame to +# start printing on. default=1. Useful when printing from +# an ERR trap function to avoid printing that function. ####################################### err-bash-trace() { - local -i argc_index=0 frame i start=${1:-0} max_indent=8 indent + local -i argc_index=0 frame i start=${_frame_start:-1} local source - local extdebug=false - if [[ $(shopt -p extdebug) == *-s* ]]; then - extdebug=true + if [[ $1 ]]; then + printf "%s\n" "$1" fi - for ((frame=0; frame < ${#FUNCNAME[@]}-1; frame++)); do + for ((frame=0; frame < ${#FUNCNAME[@]}; frame++)); do argc=${BASH_ARGC[frame]} argc_index+=$argc ((frame < start)) && continue if (( ${#BASH_SOURCE[@]} > 1 )); then - source="${BASH_SOURCE[frame+1]}:${BASH_LINENO[frame]}:" + source="${BASH_SOURCE[frame]}:${BASH_LINENO[frame-1]}:" fi - indent=$((frame-start + 1)) - indent=$((indent < max_indent ? indent : max_indent)) - printf "%${indent}s↳%sin \`%s" '' "$source" "${FUNCNAME[frame]}" - if $extdebug; then + printf " from %sin \`%s" "$source" "${FUNCNAME[frame]}" + if shopt extdebug >/dev/null; then for ((i=argc_index-1; i >= argc_index-argc; i--)); do printf " %s" "${BASH_ARGV[i]}" done @@ -75,18 +74,61 @@ err-catch() { err=$? exec >&2 set +x - echo "${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" - err-bash-trace 2 + local msg="${BASH_SOURCE[1]}:${BASH_LINENO[0]}: \`$BASH_COMMAND' returned $err" + if (( ${#FUNCNAME[@]} > 2 )); then + local _frame_start=2 + err-bash-trace "$msg" + else + echo "$msg" + fi set -e # err trap does not work within an error trap - # note :-: makes this compatible with set -u. shellcheck doesn't understand. + # note :-: makes this compatible with set -u, assigns : if unset, but shellcheck + # doesn't understand that. + # shellcheck disable=SC2154 "${_errcatch_cleanup[@]:-:}" - echo "$0: exiting with code $err" + echo "$0: exiting with status $err" exit $err } trap _err-trap ERR set -o pipefail } + +####################################### +# For interactive shells: on error, print stack trace and return +# +# Globals: +# _err_func_last Used internally. +# _err_catch_err Used internally. +# _err_catch_i Used internally. +# +# misc: All shellcheck disables for this function are false positives. +####################################### +# shellcheck disable=SC2120 +err-catch-interactive() { + # shellcheck disable=SC2034 + declare -i _err_func_last=0 + set -E; shopt -s extdebug + # shellcheck disable=SC2154 + trap '_err_catch_err=$? _trap_bc="$BASH_COMMAND" + if (( ${#FUNCNAME[@]} > _err_func_last )); then + echo ERR: \`$_trap_bc'"\'"' returned $_err_catch_err + fi + _err_func_last=${#FUNCNAME[@]} + if (( _err_func_last )); then + printf " from %s:%s:in \`%s" "${BASH_SOURCE[0]}" "$(declare -F "${FUNCNAME[0]}"|awk "{print \$2}")" "${FUNCNAME[0]}" + if shopt extdebug >/dev/null; then + for ((_err_catch_i=${BASH_ARGC[0]}-1; _err_catch_i >= 0; _err_catch_i--)); do + printf " %s" "${BASH_ARGV[_err_catch_i]}" + done + fi + echo '"\'"' + return $_err_catch_err + fi' ERR + set -o pipefail +} + + ####################################### # Undoes err-catch. turns off exit and stack trace on error. ####################################### @@ -147,4 +189,8 @@ err-exit() { } # We want this more often than not, so run it now. -err-catch +if [[ $- == *i* ]]; then + err-catch-interactive +else + err-catch +fi -- 2.25.1