Getting decent error reports in Bash when you're using 'set -e' (utcc.utoronto.ca) 166 points by zdw 11mo ago ↗ HN
[–] Grimeton 11mo ago ↗ You can just do trap 'caller 1' ERR should do the same thing. Also you should set "errtrace" (-E) and possibly "nounset" (-u) and "pipefail".
[–] o11c 11mo ago ↗ FWIW, I've grown the following which handles a few more cases. For some reason I wasn't aware of `caller` ... set -e is-oil() { test -n "$OIL_VERSION" } set -E || is-oil trap 'echo "$BASH_SOURCE:$LINENO: error: failure during early startup! Details unavailable."' ERR magic_exitvalue=$(($(kill -l CONT)+128)) backtrace() { { local status=$? if [ "$status" -eq "$magic_exitvalue" ] then echo '(omit backtrace)' exit "$magic_exitvalue" fi local max file line func argc argvi i j echo echo 'Panic! Something failed unexpectedly.' "(status $status)" echo 'While executing' "$BASH_COMMAND" echo echo Backtrace: echo max=${#BASH_LINENO[@]} let max-- # The top-most frame is "special". argvi=${BASH_ARGC[0]} for ((i=1;i<max;++i)) do file=${BASH_SOURCE[i]} line=${BASH_LINENO[i-1]} func=${FUNCNAME[i]} argc=${BASH_ARGC[i]} printf '%s:%d: ... in %q' "$file" "$line" "$func" # BASH_ARGV: ... bar foo ... # argvi ^ # argvi+argc ^ for ((j=argc-1; j>=0; --j)) do printf ' %q' ${BASH_ARGV[argvi+j]} done let argvi+=argc || true printf '\n' done if true then file=${BASH_SOURCE[i]} line=${BASH_LINENO[i-1]} printf '%s:%d: ... at top level\n' "$file" "$line" fi } >&2 exit "$magic_exitvalue" unreachable } shopt -s extdebug trap 'backtrace' ERR
[–] bjackman 11mo ago ↗ But trap doesn't "stack" (like e.g. defer in Go) so if you do this it's not available for other purposes like cleanup
[–] westurner 11mo ago ↗ Setting PS4 gets decent error reports with `set -x` (and `set -x -v`; `help set`).Here's an excerpt that shows how to set PS4 from a main() in a .env shell script for configuring devcontainer userspace: for arg in "${@}"; do case "$arg" in --debug) export __VERBOSE=1 ; #export PS4='+${LINENO}: ' ; #export PS4='+ #${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]:+${FUNCNAME[0]}()}:$(date +%T)\n+ ' ; #export PS4='+ ${LINENO} ${FUNCNAME[0]:+${FUNCNAME[0]}()}: ' ; #export PS4='+ $(printf "%-4s" ${LINENO}) | ' export PS4='+ $(printf "%-4s %-24s " ${LINENO} ${FUNCNAME[0]:+${FUNCNAME[0]}} )| ' #export PS4='+ $(printf "%-4s %-${SHLVL}s %-24s" ${LINENO} " " ${FUNCNAME[0]:+${FUNCNAME[0]}} )| ' ;; --debug-color|--debug-colors) export __VERBOSE=1 ; # red=31 export ANSI_FG_BLACK='\e[30m' #export MID_GRAY_256='\e[38;5;244m' # Example: a medium gray export _CRESET='\e[0m' export _COLOR="${ANSI_FG_BLACK}" printf "${_COLOR}DEBUG: --debug-color: This text is ANSI gray${_CRESET}\n" >&2 export PS4='+ $(printf "${_COLOR}%-4s %-24s%s |${_CRESET} " ${LINENO} "${FUNCNAME[0]:+${FUNCNAME[0]}}" )' ;; esac done This, too: function error_handler { echo "Error occurred on line $(caller)" >&2 awk 'NR>L-4 && NR<L+4 { printf "%-5d%3s%s\n",NR,(NR==L?">>>":""),$0 }' L=$1 $0 >&2 } if (echo "${SHELL}" | grep "bash"); then trap 'error_handler $LINENO' ERR fi
[–] 9woc 11mo ago ↗ beware of using this. any operations that returns non-zero exit status will cause immediately exit
6 comments
[ 3.8 ms ] story [ 24.5 ms ] threadHere's an excerpt that shows how to set PS4 from a main() in a .env shell script for configuring devcontainer userspace:
This, too: