@EdMorton Thanks a lot, you are the best! :)
So I got this now and it seems to work well:
set -E
trap 'trap_err' ERR
export -a DEBUG_STACK_LAST=()
trap_err() {
local -n a=DEBUG_STACK_LAST
local -n b=BASH_LINENO
local -i is_substack=0
((${#a[@]} == ${#b[@]}+1)) && { is_substack=1; for i in ${!b[@]}; do
((${a[$((i+1))]} != ${b[$i]})) && is_substack=0 && break
done; }
a=(${b[@]})
((is_substack == 1)) && return
echo "D: $BASH_COMMAND . ${FUNCNAME[@]:1} . ${BASH_LINENO[@]}"
}
I have to test more cases, but I made a new test scenario:
f() {
echo "* $FUNCNAME here: $@"
stat /from/f
}
g() {
echo "* $FUNCNAME here: $@"
stat /from/g ||:
}
h() {
echo "* $FUNCNAME here: $@"
f "$@ ~ from h"
g "$@ ~ from h"
}
echo; echo "** functions"
f round 1
g round 1
h round 1
echo; echo "** subshells"
(f round 2)
(g round 2)
(h round 2)
echo; echo "** plain"
stat /from/main ||:
What I particularly like is that if the ERR trapped call from a subshell, I get to see it (duplicate), but I do not get to see the extras from diving down the stack. Here:
** functions
* f here: round 1
stat: cannot statx '/from/f': No such file or directory
D: stat /from/f . f main . 27 44 0
* g here: round 1
stat: cannot statx '/from/g': No such file or directory
* h here: round 1
* f here: round 1 ~ from h
stat: cannot statx '/from/f': No such file or directory
D: stat /from/f . f h main . 27 38 46 0
* g here: round 1 ~ from h
stat: cannot statx '/from/g': No such file or directory
** subshells
* f here: round 2
stat: cannot statx '/from/f': No such file or directory
D: stat /from/f . f main . 27 50 0
D: ( f round 2 ) . main . 50 0
* g here: round 2
stat: cannot statx '/from/g': No such file or directory
* h here: round 2
* f here: round 2 ~ from h
stat: cannot statx '/from/f': No such file or directory
D: stat /from/f . f h main . 27 38 52 0
* g here: round 2 ~ from h
stat: cannot statx '/from/g': No such file or directory
** plain
stat: cannot statx '/from/main': No such file or directory
I never see the same stat
command twice, but I do get to see D: ( f round 2 ) . main . 50 0
as an extra there. I think it's actually better than NOT showing it. I feel it's very little extra work for getting your PoC robust.