1 ## compare_shells: bash
2 ## oils_failures_allowed: 1
3
4 # Test call stack introspection. There are a bunch of special variables
5 # defined here:
6 #
7 # https://www.gnu.org/software/bash/manual/html_node/Bash-Variables.html
8 #
9 # - The shell function ${FUNCNAME[$i]} is defined in the file
10 # ${BASH_SOURCE[$i]} and called from ${BASH_SOURCE[$i+1]}
11 #
12 # - ${BASH_LINENO[$i]} is the line number in the source file
13 # (${BASH_SOURCE[$i+1]}) where ${FUNCNAME[$i]} was called (or
14 # ${BASH_LINENO[$i-1]} if referenced within another shell function).
15 #
16 # - For instance, ${FUNCNAME[$i]} was called from the file
17 # ${BASH_SOURCE[$i+1]} at line number ${BASH_LINENO[$i]}. The caller builtin
18 # displays the current call stack using this information.
19 #
20 # So ${BASH_SOURCE[@]} doesn't line up with ${BASH_LINENO}. But
21 # ${BASH_SOURCE[0]} does line up with $LINENO!
22 #
23 # Geez.
24 #
25 # In other words, BASH_SOURCE is about the DEFINITION. While FUNCNAME and
26 # BASH_LINENO are about the CALL.
27
28
29 #### ${FUNCNAME[@]} array
30 g() {
31 argv.py "${FUNCNAME[@]}"
32 }
33 f() {
34 argv.py "${FUNCNAME[@]}"
35 g
36 argv.py "${FUNCNAME[@]}"
37 }
38 f
39 ## STDOUT:
40 ['f']
41 ['g', 'f']
42 ['f']
43 ## END
44
45 #### FUNCNAME with source (scalar or array)
46 cd $REPO_ROOT
47
48 # Comments on bash quirk:
49 # https://github.com/oilshell/oil/pull/656#issuecomment-599162211
50
51 f() {
52 . spec/testdata/echo-funcname.sh
53 }
54 g() {
55 f
56 }
57
58 g
59 echo -----
60
61 . spec/testdata/echo-funcname.sh
62 echo -----
63
64 argv.py "${FUNCNAME[@]}"
65
66 # Show bash inconsistency. FUNCNAME doesn't behave like a normal array.
67 case $SH in
68 (bash)
69 echo -----
70 a=('A')
71 argv.py ' @' "${a[@]}"
72 argv.py ' 0' "${a[0]}"
73 argv.py '${}' "${a}"
74 argv.py ' $' "$a"
75 ;;
76 esac
77
78 ## STDOUT:
79 [' @', 'source', 'f', 'g']
80 [' 0', 'source']
81 ['${}', 'source']
82 [' $', 'source']
83 -----
84 [' @', 'source']
85 [' 0', 'source']
86 ['${}', 'source']
87 [' $', 'source']
88 -----
89 []
90 ## END
91 ## BUG bash STDOUT:
92 [' @', 'source', 'f', 'g']
93 [' 0', 'source']
94 ['${}', 'source']
95 [' $', 'source']
96 -----
97 [' @', 'source']
98 [' 0', 'source']
99 ['${}', '']
100 [' $', '']
101 -----
102 []
103 -----
104 [' @', 'A']
105 [' 0', 'A']
106 ['${}', 'A']
107 [' $', 'A']
108 ## END
109
110
111 #### BASH_SOURCE and BASH_LINENO scalar or array (e.g. for virtualenv)
112 cd $REPO_ROOT
113
114 # https://github.com/pypa/virtualenv/blob/master/virtualenv_embedded/activate.sh
115 # https://github.com/akinomyoga/ble.sh/blob/6f6c2e5/ble.pp#L374
116
117 argv.py "$BASH_SOURCE" # SimpleVarSub
118 argv.py "${BASH_SOURCE}" # BracedVarSub
119 argv.py "$BASH_LINENO" # SimpleVarSub
120 argv.py "${BASH_LINENO}" # BracedVarSub
121 argv.py "$FUNCNAME" # SimpleVarSub
122 argv.py "${FUNCNAME}" # BracedVarSub
123 echo __
124 source spec/testdata/bash-source-string.sh
125
126 ## STDOUT:
127 ['']
128 ['']
129 ['']
130 ['']
131 ['']
132 ['']
133 __
134 ['spec/testdata/bash-source-string.sh']
135 ['spec/testdata/bash-source-string.sh']
136 ['11']
137 ['11']
138 ____
139 ['spec/testdata/bash-source-string2.sh']
140 ['spec/testdata/bash-source-string2.sh']
141 ['11']
142 ['11']
143 ## END
144
145
146 #### ${FUNCNAME} with prefix/suffix operators
147
148 check() {
149 argv.py "${#FUNCNAME}"
150 argv.py "${FUNCNAME::1}"
151 argv.py "${FUNCNAME:1}"
152 }
153 check
154 ## STDOUT:
155 ['5']
156 ['c']
157 ['heck']
158 ## END
159
160 #### operators on FUNCNAME
161 check() {
162 argv.py "${FUNCNAME}"
163 argv.py "${#FUNCNAME}"
164 argv.py "${FUNCNAME::1}"
165 argv.py "${FUNCNAME:1}"
166 }
167 check
168 ## status: 0
169 ## STDOUT:
170 ['check']
171 ['5']
172 ['c']
173 ['heck']
174 ## END
175
176 #### ${FUNCNAME} and "set -u" (OSH regression)
177 set -u
178 argv.py "$FUNCNAME"
179 ## status: 1
180 ## stdout-json: ""
181
182 #### $((BASH_LINENO)) (scalar form in arith)
183 check() {
184 echo $((BASH_LINENO))
185 }
186 check
187 ## stdout: 4
188
189 #### ${BASH_SOURCE[@]} with source and function name
190 cd $REPO_ROOT
191
192 argv.py "${BASH_SOURCE[@]}"
193 source spec/testdata/bash-source-simple.sh
194 f
195 ## STDOUT:
196 []
197 ['spec/testdata/bash-source-simple.sh']
198 ['spec/testdata/bash-source-simple.sh']
199 ## END
200
201 #### ${BASH_SOURCE[@]} with line numbers
202 cd $REPO_ROOT
203
204 $SH spec/testdata/bash-source.sh
205 ## STDOUT:
206 ['begin F funcs', 'f', 'main']
207 ['begin F files', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
208 ['begin F lines', '21', '0']
209 ['G funcs', 'g', 'f', 'main']
210 ['G files', 'spec/testdata/bash-source-2.sh', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
211 ['G lines', '15', '21', '0']
212 ['end F funcs', 'f', 'main']
213 ['end F', 'spec/testdata/bash-source.sh', 'spec/testdata/bash-source.sh']
214 ['end F lines', '21', '0']
215 ## END
216
217 #### ${BASH_LINENO[@]} is a stack of line numbers for function calls
218 # note: it's CALLS, not DEFINITIONS.
219 g() {
220 argv.py G "${BASH_LINENO[@]}"
221 }
222 f() {
223 argv.py 'begin F' "${BASH_LINENO[@]}"
224 g # line 6
225 argv.py 'end F' "${BASH_LINENO[@]}"
226 }
227 argv.py ${BASH_LINENO[@]}
228 f # line 9
229 ## STDOUT:
230 []
231 ['begin F', '10']
232 ['G', '6', '10']
233 ['end F', '10']
234 ## END
235
236 #### Locations with temp frame
237
238 cd $REPO_ROOT
239
240 $SH spec/testdata/bash-source-pushtemp.sh
241
242 ## STDOUT:
243 F
244 G
245 STACK:spec/testdata/bash-source-pushtemp.sh:g:3
246 STACK:spec/testdata/bash-source-pushtemp.sh:f:19
247 STACK:spec/testdata/bash-source-pushtemp.sh:main:0
248 ## END
249
250 #### Locations when sourcing
251
252 cd $REPO_ROOT
253
254 # like above test case, but we source
255
256 # bash location doesn't make sense:
257 # - It says 'source' happens at line 1 of bash-source-pushtemp. Well I think
258 # - It really happens at line 2 of '-c' ! I guess that's to line up
259 # with the 'main' frame
260
261 $SH -c 'true;
262 source spec/testdata/bash-source-pushtemp.sh'
263
264 ## BUG bash STDOUT:
265 F
266 G
267 STACK:spec/testdata/bash-source-pushtemp.sh:g:3
268 STACK:spec/testdata/bash-source-pushtemp.sh:f:19
269 STACK:spec/testdata/bash-source-pushtemp.sh:source:1
270 ## END
271
272 ## OK osh STDOUT:
273 F
274 G
275 STACK:spec/testdata/bash-source-pushtemp.sh:g:3
276 STACK:spec/testdata/bash-source-pushtemp.sh:f:19
277 STACK:spec/testdata/bash-source-pushtemp.sh:source:2
278 ## END
279
280 #### Sourcing inside function grows the debug stack
281
282 cd $REPO_ROOT
283
284 $SH spec/testdata/bash-source-source.sh
285
286 ## STDOUT:
287 F
288 G
289 STACK:spec/testdata/bash-source-pushtemp.sh:g:3
290 STACK:spec/testdata/bash-source-pushtemp.sh:f:19
291 STACK:spec/testdata/bash-source-pushtemp.sh:source:2
292 STACK:spec/testdata/bash-source-source.sh:mainfunc:6
293 STACK:spec/testdata/bash-source-source.sh:main2:10
294 STACK:spec/testdata/bash-source-source.sh:main1:13
295 STACK:spec/testdata/bash-source-source.sh:main:0
296 ## END