Created
June 24, 2021 13:48
-
-
Save matlinuxer2/18ebbb81432c9edd631275c24bdf4d7e to your computer and use it in GitHub Desktop.
bash backtrace
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env bash | |
function throw(){ | |
local msg="${1}" | |
_ERR_MSG_="$msg" | |
kill -s USR2 $BASHPID | |
} | |
function backtrace | |
{ | |
# Hide the traceback() call. | |
local -i cnt=${#BASH_SOURCE[@]} # call stack 共 N 個, [0..N-1] | |
local -i start=$(( ${1:-0} )) | |
local -i end=$(( $cnt - 1 )) | |
local -i i=0 | |
local -i max1=0 | |
local -i max2=0 | |
max1=$( for (( k=$start+1; k <=$end; k++ )); do echo "${BASH_SOURCE[$k]}" ; done | wc --max-line-length ) | |
max2=$( for (( k=$start ; k <=$end; k++ )); do echo "${BASH_LINENO[$k]}" ; done | wc --max-line-length ) | |
( | |
printf "\n" | |
printf "+----------------------------------\n" | |
printf "|Traceback (most recent call last):\n" | |
for ((i=${end}; i >= ${start}; i--)); do | |
local func="${FUNCNAME[$i]}" | |
local file="${BASH_SOURCE[$i+1]}" | |
[ $i -eq $end ] && file="${BASH_SOURCE[$end]}" # 效正最後的邊界值 | |
local line="${BASH_LINENO[$i]}" | |
local padding=$(( $end - $i + 3 )) | |
printf "| %${max1}s:%-${max2}s %${padding}s %s()\n" "${file}" "${line}" "\\->" "${func}" | |
done | |
printf "+----------------------------------\n" | |
) | perl -pe 's/^/ /g' | perl -pe 's/^\s*$//g' | cat 1>&2 | |
} | |
function set_err_policy(){ | |
local policy="$1" | |
local -i cnt=${#BASH_SOURCE[@]} # call stack 共 N 個, [0..N-1] | |
local -i end=$(( $cnt - 1 )) | |
local -i i=1 | |
local func="${FUNCNAME[$i]}" | |
local file="${BASH_SOURCE[$i+1]}" | |
[ $i -eq $end ] && file="${BASH_SOURCE[$end]}" # 效正最後的邊界值 | |
local line="${BASH_LINENO[$i]}" | |
local file="$( echo $file | perl -pe 's/\./_/g' | perl -pe 's/\//_/g' )" | |
export ${file}_${line}_${func}="$policy" | |
} | |
function get_err_policy(){ | |
# Hide the traceback() call. | |
local -i cnt=${#BASH_SOURCE[@]} # call stack 共 N 個, [0..N-1] | |
local -i start=$(( ${1:-0} + 1 )) | |
local -i end=$(( $cnt - 1 )) | |
local -i i=0 | |
local res="" | |
for (( i=${start}; i <= ${end}; i++ )); do | |
local func="${FUNCNAME[$i]}" | |
local file="${BASH_SOURCE[$i+1]}" | |
[ $i -eq $end ] && file="${BASH_SOURCE[$end]}" # 效正最後的邊界值 | |
local line="${BASH_LINENO[$i]}" | |
local file="$( echo $file | perl -pe 's/\./_/g' | perl -pe 's/\//_/g' )" | |
local policy=$( eval "echo \${${file}_${line}_${func}}" ) | |
[ -n "$policy" ] && res="$policy" && break | |
#printf " %s_%s_%s => %s\n" "${file}" "${line}" "${func}" "$policy" 1>&2 | |
done | |
echo $res | |
} | |
function _err_handler(){ | |
local _err_code="$?" | |
local _err_msg="$_EX_MSG_" ; unset _ERR_MSG_ | |
local _err_policy=$( get_err_policy 1 ) | |
[ $_err_code -ne 99 ] && [ $_err_policy != "silent" ] && backtrace 1 # 若不是 bubble 的 error event, 就 show backtrace ( 除了 silent 外 ) | |
case "$_err_policy" in | |
silent) { | |
return 0; | |
} | |
;; | |
keepgoing) { | |
return 0; | |
} | |
;; | |
bubble) { | |
[ ${#BASH_SOURCE[@]} -gt 2 ] && return 99 || exit 99 | |
} | |
;; | |
*) { | |
return 0; | |
} | |
;; | |
esac | |
} | |
function _err_handling_eval_(){ | |
cat <<-EOD | |
set -o errtrace; | |
trap "_err_handler || return 99;" ERR; | |
trap "backtrace 1; return 99;" USR2; | |
trap "[ \\\$? -ne 99 -a \\\$? -ne 0 ] && { backtrace 1; }" EXIT; | |
EOD | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment