OILS / spec / builtin-trap-bash.test.sh View on Github | oilshell.org

557 lines, 342 significant
1## oils_failures_allowed: 1
2## compare_shells: bash
3
4# Notes on bash semantics:
5
6# https://www.gnu.org/software/bash/manual/bash.html
7#
8# Commands specified with a DEBUG trap are executed before every simple
9# command, for command, case command, select command, every arithmetic for
10# command, and before the first command executes in a shell function. The DEBUG
11# trap is not inherited by shell functions unless the function has been given
12# the trace attribute or the functrace option has been enabled using the shopt
13# builtin. The extdebug shell option has additional effects on the DEBUG trap.
14
15# The trap builtin (see Bourne Shell Builtins) allows an ERR pseudo-signal
16# specification, similar to EXIT and DEBUG. Commands specified with an ERR trap
17# are executed after a simple command fails, with a few exceptions. The ERR
18# trap is not inherited by shell functions unless the -o errtrace option to the
19# set builtin is enabled.
20
21
22#### trap -l
23trap -l | grep INT >/dev/null
24## status: 0
25
26
27#### trap -p
28
29trap 'echo exit' EXIT
30
31trap -p > parent.txt
32
33grep EXIT parent.txt >/dev/null
34if test $? -eq 0; then
35 echo shown
36else
37 echo not shown
38fi
39
40## STDOUT:
41shown
42exit
43## END
44
45#### trap -p in child is BUGGY in bash
46
47# It shows the trap even though it doesn't execute it!
48
49trap 'echo exit' EXIT
50
51trap -p | cat > child.txt
52
53grep EXIT child.txt >/dev/null
54if test $? -eq 0; then
55 echo shown
56else
57 echo not shown
58fi
59
60## STDOUT:
61not shown
62exit
63## END
64## BUG bash STDOUT:
65shown
66exit
67## END
68
69#### trap DEBUG ignores $?
70debuglog() {
71 echo " [$@]"
72 return 42 # IGNORED FAILURE
73}
74
75trap 'debuglog $LINENO' DEBUG
76
77echo status=$?
78echo A
79echo status=$?
80echo B
81echo status=$?
82
83## STDOUT:
84 [8]
85status=0
86 [9]
87A
88 [10]
89status=0
90 [11]
91B
92 [12]
93status=0
94## END
95
96#### but trap DEBUG respects errexit
97set -o errexit
98
99debuglog() {
100 echo " [$@]"
101 return 42
102}
103
104trap 'debuglog $LINENO' DEBUG
105
106echo status=$?
107echo A
108echo status=$?
109echo B
110echo status=$?
111
112## status: 42
113## STDOUT:
114 [10]
115## END
116
117#### trap DEBUG with 'return'
118
119debuglog() {
120 echo " [$@]"
121}
122
123trap 'debuglog $LINENO; return 42' DEBUG
124
125echo status=$?
126echo A
127echo status=$?
128echo B
129echo status=$?
130
131## status: 0
132
133## STDOUT:
134 [7]
135status=0
136 [8]
137A
138 [9]
139status=0
140 [10]
141B
142 [11]
143status=0
144## END
145
146# OSH doesn't ignore this
147
148## OK osh status: 42
149## OK osh STDOUT:
150 [7]
151## END
152
153#### trap DEBUG with 'exit'
154debuglog() {
155 echo " [$@]"
156}
157
158trap 'debuglog $LINENO; exit 42' DEBUG
159
160echo status=$?
161echo A
162echo status=$?
163echo B
164echo status=$?
165
166## status: 42
167## STDOUT:
168 [7]
169## END
170
171
172
173#### trap DEBUG with non-compound commands
174case $SH in (dash|mksh) exit ;; esac
175
176debuglog() {
177 echo " [$@]"
178}
179trap 'debuglog $LINENO' DEBUG
180
181echo a
182echo b; echo c
183
184echo d && echo e
185echo f || echo g
186
187(( h = 42 ))
188[[ j == j ]]
189
190var=value
191
192readonly r=value
193
194## STDOUT:
195 [8]
196a
197 [9]
198b
199 [9]
200c
201 [11]
202d
203 [11]
204e
205 [12]
206f
207 [14]
208 [15]
209 [17]
210 [19]
211## END
212
213#### trap DEBUG and control flow
214
215debuglog() {
216 echo " [$@]"
217}
218trap 'debuglog $LINENO' DEBUG
219
220while true; do
221 echo hello
222 break
223done
224
225## STDOUT:
226 [6]
227 [7]
228hello
229 [8]
230## END
231## STDOUT:
232 [6]
233 [7]
234hello
235 [8]
236## END
237
238#### trap DEBUG and command sub / subshell
239case $SH in (dash|mksh) exit ;; esac
240
241debuglog() {
242 echo " [$@]"
243}
244trap 'debuglog $LINENO' DEBUG
245
246echo "result = $(echo command sub; echo two)"
247( echo subshell
248 echo two
249)
250echo done
251
252## STDOUT:
253 [8]
254result = command sub
255two
256subshell
257two
258 [12]
259done
260## END
261
262#### trap DEBUG not run in forked interpreter for first pipeline part
263
264debuglog() {
265 #echo " PID=$$ BASHPID=$BASHPID LINENO=$1"
266 echo " LINENO=$1"
267}
268trap 'debuglog $LINENO' DEBUG
269
270{ echo pipe1;
271 echo pipe2; } \
272 | cat
273echo ok
274
275## STDOUT:
276 LINENO=8
277pipe1
278pipe2
279 LINENO=9
280ok
281## END
282
283#### One 'echo' in first pipeline part - why does bash behave differently from case above?
284
285# TODO: bash runs the trap 3 times, and osh only twice. I don't see why. Is
286# it because Process::Run() does trap_state.ClearForSubProgram()? Probably
287#echo top PID=$$ BASHPID=$BASHPID
288#shopt -s lastpipe
289
290debuglog() {
291 #echo " PID=$$ BASHPID=$BASHPID LINENO=$1"
292 #echo " LINENO=$1 $BASH_COMMAND"
293 # LINENO=6 echo pipeline
294 # LINENO=7 cat
295 echo " LINENO=$1"
296}
297trap 'debuglog $LINENO' DEBUG
298
299echo pipeline \
300 | cat
301echo ok
302
303## STDOUT:
304 LINENO=6
305 LINENO=7
306pipeline
307 LINENO=8
308ok
309## END
310## OK osh STDOUT:
311 LINENO=7
312pipeline
313 LINENO=8
314ok
315## END
316
317#### trap DEBUG and pipeline (lastpipe difference)
318debuglog() {
319 echo " [$@]"
320}
321trap 'debuglog $LINENO' DEBUG
322
323# gets run for each one of these
324{ echo a; echo b; }
325
326# only run for the last one, maybe I guess because traps aren't inherited?
327{ echo x; echo y; } | wc -l
328
329# bash runs for all of these, but OSH doesn't because we have SubProgramThunk
330# Hm.
331date | cat | wc -l
332
333date |
334 cat |
335 wc -l
336
337## STDOUT:
338 [6]
339a
340 [6]
341b
342 [8]
3432
344 [10]
345 [10]
346 [10]
3471
348 [12]
349 [13]
350 [14]
3511
352## END
353
354# Marking OK due to lastpipe execution difference
355
356## OK osh STDOUT:
357 [6]
358a
359 [6]
360b
361 [8]
3622
363 [10]
3641
365 [14]
3661
367## END
368
369#### trap DEBUG function call
370debuglog() {
371 echo " [$@]"
372}
373trap 'debuglog $LINENO' DEBUG
374
375f() {
376 local mylocal=1
377 for i in "$@"; do
378 echo i=$i
379 done
380}
381
382f A B # executes ONCE here, but does NOT go into the function call
383
384echo next
385
386f X Y
387
388echo ok
389
390## STDOUT:
391 [13]
392i=A
393i=B
394 [15]
395next
396 [17]
397i=X
398i=Y
399 [19]
400ok
401## END
402
403#### trap DEBUG case
404debuglog() {
405 echo " [$@]"
406}
407trap 'debuglog $LINENO' DEBUG
408
409name=foo.py
410
411case $name in
412 *.py)
413 echo python
414 ;;
415 *.sh)
416 echo shell
417 ;;
418esac
419echo ok
420
421## STDOUT:
422 [6]
423 [8]
424 [10]
425python
426 [16]
427ok
428## END
429
430#### trap DEBUG for each
431
432debuglog() {
433 echo " [$@]"
434}
435trap 'debuglog $LINENO' DEBUG
436
437for x in 1 2; do
438 echo x=$x
439done
440
441echo ok
442
443## STDOUT:
444 [6]
445 [7]
446x=1
447 [6]
448 [7]
449x=2
450 [10]
451ok
452## END
453
454# NOT matching bash right now because 'while' loops don't have it
455# And we have MORE LOOPS
456#
457# What we really need is a trap that runs in the main loop and TELLS you what
458# kind of node it is?
459
460## N-I osh STDOUT:
461 [7]
462x=1
463 [7]
464x=2
465 [10]
466ok
467## END
468
469#### trap DEBUG for expr
470debuglog() {
471 echo " [$@]"
472}
473trap 'debuglog $LINENO' DEBUG
474
475for (( i =3 ; i < 5; ++i )); do
476 echo i=$i
477done
478
479echo ok
480
481## STDOUT:
482 [6]
483 [6]
484 [7]
485i=3
486 [6]
487 [6]
488 [7]
489i=4
490 [6]
491 [6]
492 [10]
493ok
494## END
495## N-I osh STDOUT:
496 [7]
497i=3
498 [7]
499i=4
500 [10]
501ok
502## END
503
504#### trap DEBUG if while
505debuglog() {
506 echo " [$@]"
507}
508trap 'debuglog $LINENO' DEBUG
509
510if test x = x; then
511 echo if
512fi
513
514while test x != x; do
515 echo while
516done
517
518## STDOUT:
519 [6]
520 [7]
521if
522 [10]
523## END
524
525
526#### trap RETURN
527profile() {
528 echo "profile [$@]"
529}
530g() {
531 echo --
532 echo g
533 echo --
534 return
535}
536f() {
537 echo --
538 echo f
539 echo --
540 g
541}
542# RETURN trap doesn't fire when a function returns, only when a script returns?
543# That's not what the manual says.
544trap 'profile x y' RETURN
545f
546. $REPO_ROOT/spec/testdata/return-helper.sh
547## status: 42
548## STDOUT:
549--
550f
551--
552--
553g
554--
555return-helper.sh
556profile [x y]
557## END