Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save matlinuxer2/18ebbb81432c9edd631275c24bdf4d7e to your computer and use it in GitHub Desktop.
Save matlinuxer2/18ebbb81432c9edd631275c24bdf4d7e to your computer and use it in GitHub Desktop.
bash backtrace
#!/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