OILS / demo / bash-call-stack.sh View on Github | oils.pub

121 lines, 55 significant
1#!/usr/bin/env bash
2#
3# Usage:
4# demo/bash-call-stack.sh <function name>
5
6set -o nounset
7set -o pipefail
8set -o errexit
9
10print-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
24f() {
25 echo 'hi from f'
26 g
27}
28
29g() {
30 echo 'hi from g'
31 print-stack
32}
33
34no-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
46do-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
63error-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
72do-undefined-var() {
73 echo unset
74 echo $oops
75}
76
77error-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
88python() {
89 cat >_tmp/callstack.py <<EOF
90def f():
91 print("hi from f")
92 exec("g()")
93
94def g():
95 print("hi from g")
96 raise RuntimeError()
97
98f()
99EOF
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
110def h():
111 import callstack
112
113h()
114EOF
115
116 # 5 frames: h() imprt callstack f() g() raise
117 python2 _tmp/callmain.py
118}
119
120"$@"
121