From: Ian Kelling Date: Wed, 6 Nov 2019 00:57:34 +0000 (-0500) Subject: more accurate interactive trace, refactor X-Git-Url: https://vcs.fsf.org/?p=errhandle.git;a=commitdiff_plain;h=5f3350ecaad1902304fe2338236450b56711ac9d more accurate interactive trace, refactor --- diff --git a/err b/err index 3be1671..8162070 100644 --- a/err +++ b/err @@ -62,7 +62,7 @@ err-catch() { # this is sourced from a startup file, and you use a login shell to # run a command. Avoid doing that if you want function arguments in # your trace. - if [[ $- != *c* ]] && ! shopt login_shell >/dev/null; then + if [[ $- != *c* ]] || ! shopt login_shell >/dev/null; then shopt -s extdebug fi _err-trap() { @@ -88,53 +88,67 @@ err-catch() { } +####################################### +# Internal function for err-catch-interactive. +# Prints stack trace from interactive shell trap. +# Usage: see err-catch-interactive +####################################### + +_err-bash-trace-interactive() { + local ret bash_command argc pattern i + # We have these passed to us because they are lost inside the + # function. + ret=$1 + bash_command="$2" + argc=$(( $3 - 1 )) + shift 3 + argv=("$@") + for pattern in "${err_catch_ignore[@]}"; do + # shellcheck disable=SC2053 + if [[ ${BASH_SOURCE[0]} == $pattern ]]; then + return 0 + fi + done + if (( ${#FUNCNAME[@]} > _err_func_last )); then + echo ERR: \`$bash_command\' returned $ret + fi + _err_func_last=${#FUNCNAME[@]} + if (( _err_func_last > 1 )); then + printf " from \`%s" "${FUNCNAME[1]}" + if shopt extdebug >/dev/null; then + for ((i=argc; i >= 0; i--)); do + printf " %s" "${argv[i]}" + done + fi + printf "\' defined at %s:%s\n" "${BASH_SOURCE[1]}" "$(declare -F "${FUNCNAME[1]}"|awk "{print \$2}")" + return $ret + fi +} + ####################################### # For interactive shells: on error, print stack trace and return # +# Note: calling line number is not available, so we print function +# definition lines. +# # Globals: # err_catch_ignore Array containing glob patterns to test against filenames to ignore # errors from. Initialized to ignore bash-completion scripts on debian # based systems. -# _err_func_last Used internally. -# _err_catch_err Used internally. -# _err_catch_i Used internally. -# _err_catch_ignore Used internally. +# _err_func_last Used internally in err-bash-trace-interactive # -# misc: All shellcheck disables for this function are false positives. ####################################### -# shellcheck disable=SC2120 err-catch-interactive() { - err_catch_ignore=( - '/etc/bash_completion.d/*' - ) - # shellcheck disable=SC2034 + if ! test ${err_catch_ignore+defined}; then + err_catch_ignore=( + '/etc/bash_completion.d/*' + '*/bash-completion/*' + ) + fi declare -i _err_func_last=0 set -E; shopt -s extdebug # shellcheck disable=SC2154 - trap '_err_catch_err=$? _trap_bc="$BASH_COMMAND" - _err_catch_ignore=false - for _err_catch_i in "${err_catch_ignore[@]}"; do - if [[ ${BASH_SOURCE[0]} == $_err_catch_i ]]; then - _err_catch_ignore=true - break - fi - done - if ! $_err_catch_ignore; then - 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 - fi' ERR + trap '_err-bash-trace-interactive $? "$BASH_COMMAND" ${BASH_ARGC[0]} "${BASH_ARGV[@]}"' ERR set -o pipefail }