1 | #!/usr/bin/env bash
|
2 | #
|
3 | # Usage:
|
4 | # demo/bash-call-stack.sh <function name>
|
5 |
|
6 | set -o nounset
|
7 | set -o pipefail
|
8 | set -o errexit
|
9 |
|
10 | print-stack() {
|
11 | local n=${#BASH_SOURCE[@]}
|
12 | for (( i = 0; i < n; ++i)); do
|
13 | # off by one adjustment seems more accurate, similar to
|
14 | # https://opensource.com/article/22/7/print-stack-trace-bash-scripts
|
15 | if false; then
|
16 | echo "STACK:${BASH_SOURCE[i]}:${FUNCNAME[i+1]:-}:${BASH_LINENO[i]}"
|
17 | else
|
18 | echo "STACK:${BASH_SOURCE[i]}:${FUNCNAME[i]}:${BASH_LINENO[i]}"
|
19 | fi
|
20 | done
|
21 | }
|
22 |
|
23 |
|
24 | f() {
|
25 | echo 'hi from f'
|
26 | g
|
27 | }
|
28 |
|
29 | g() {
|
30 | echo 'hi from g'
|
31 | print-stack
|
32 | }
|
33 |
|
34 | no-error() {
|
35 | # -1 position is the bottom of the stack
|
36 | #
|
37 | # It has has demo/bash-stack.sh:main:0
|
38 | #
|
39 | # This is tested in spec/introspect.sh
|
40 |
|
41 | #PS4='+ ${BASH_SOURCE[-1]}:${FUNCNAME[-1]}:${BASH_LINENO[-1]} '
|
42 | #set -x
|
43 | f
|
44 | }
|
45 |
|
46 | do-command-error() {
|
47 | echo 'hi from h'
|
48 |
|
49 | # Hm, in OSH this does trigger the err trap, but not in bash
|
50 |
|
51 | if false; then
|
52 | shopt -s failglob
|
53 | echo *.zyzyz
|
54 | fi
|
55 |
|
56 | # simple command error
|
57 | # false
|
58 |
|
59 | # pipeline error
|
60 | false | true
|
61 | }
|
62 |
|
63 | error-command() {
|
64 | ### 'false' causes errexit
|
65 |
|
66 | set -o errtrace # needed to keep it active
|
67 | trap 'print-stack' ERR
|
68 |
|
69 | do-command-error
|
70 | }
|
71 |
|
72 | do-undefined-var() {
|
73 | echo unset
|
74 | echo $oops
|
75 | }
|
76 |
|
77 | error-undefined-var() {
|
78 | ### undefined var - no stack trace!
|
79 |
|
80 | # I guess you can argue this is a programming bug
|
81 |
|
82 | set -o errtrace # needed to keep it active
|
83 | trap 'print-stack' ERR
|
84 |
|
85 | do-undefined-var
|
86 | }
|
87 |
|
88 | python() {
|
89 | cat >_tmp/callstack.py <<EOF
|
90 | def f():
|
91 | print("hi from f")
|
92 | exec("g()")
|
93 |
|
94 | def g():
|
95 | print("hi from g")
|
96 | raise RuntimeError()
|
97 |
|
98 | f()
|
99 | EOF
|
100 |
|
101 | echo
|
102 | echo
|
103 | set +o errexit
|
104 |
|
105 | # 3 frames: <module> f g
|
106 | # and quotes the code
|
107 | python2 _tmp/callstack.py
|
108 |
|
109 | cat >_tmp/callmain.py <<EOF
|
110 | def h():
|
111 | import callstack
|
112 |
|
113 | h()
|
114 | EOF
|
115 |
|
116 | # 5 frames: h() imprt callstack f() g() raise
|
117 | python2 _tmp/callmain.py
|
118 | }
|
119 |
|
120 | "$@"
|
121 |
|