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

554 lines, 281 significant
1## oils_failures_allowed: 4
2## compare_shells: bash mksh ash
3
4# Notes on bash semantics:
5#
6# https://www.gnu.org/software/bash/manual/bash.html
7#
8# The trap builtin (see Bourne Shell Builtins) allows an ERR pseudo-signal
9# specification, similar to EXIT and DEBUG. Commands specified with an ERR trap
10# are executed after a simple command fails, with a few exceptions. The ERR
11# trap is not inherited by shell functions unless the -o errtrace option to the
12# set builtin is enabled.
13
14
15#### trap can use original $LINENO
16
17trap 'echo line=$LINENO' ERR
18
19false
20false
21echo ok
22
23## STDOUT:
24line=3
25line=4
26ok
27## END
28
29#### trap ERR and set -o errexit
30
31trap 'echo line=$LINENO' ERR
32
33false
34echo a
35
36set -o errexit
37
38echo b
39false # trap executed, and executation also halts
40echo c # doesn't get here
41
42## status: 1
43## STDOUT:
44line=3
45a
46b
47line=9
48## END
49
50#### trap ERR and errexit disabled context
51
52trap 'echo line=$LINENO' ERR
53
54false
55echo a
56
57set -o errexit
58
59echo b
60if false; then
61 echo xx
62fi
63echo c # doesn't get here
64
65## STDOUT:
66line=3
67a
68b
69c
70## END
71
72#### trap ERR and if statement
73
74if test -f /nope; then echo file exists; fi
75
76trap 'echo err' ERR
77#trap 'echo line=$LINENO' ERR
78
79if test -f /nope; then echo file exists; fi
80
81## STDOUT:
82## END
83
84
85#### trap ERR and || conditional
86
87trap 'echo line=$LINENO' ERR
88
89false || false || false
90echo ok
91
92false && false
93echo ok
94
95## STDOUT:
96line=3
97ok
98ok
99## END
100
101#### trap ERR and pipeline
102
103# mksh and bash have different line numbers in this case
104#trap 'echo line=$LINENO' ERR
105trap 'echo line=$LINENO' ERR
106
107# it's run for the last 'false'
108false | false | false
109
110{ echo pipeline; false; } | false | false
111
112# it's never run here
113! true
114! false
115
116## STDOUT:
117line=3
118line=5
119## END
120
121## BUG mksh/ash STDOUT:
122line=1
123line=1
124## END
125
126
127#### trap ERR pipelines without simple commands
128
129trap 'echo assign' ERR
130a=$(false) | a=$(false) | a=$(false)
131
132# anomaly - it gets printed twice?
133trap 'echo subshell' ERR
134(false) | (false) | (false) | (false)
135
136trap 'echo dparen' ERR
137(( 0 )) | (( 0 )) | (( 0 ))
138
139trap 'echo dbracket' ERR
140[[ a = b ]] | [[ a = b ]] | [[ a = b ]]
141
142echo ok
143
144## STDOUT:
145assign
146subshell
147dparen
148dbracket
149ok
150## END
151
152## BUG bash STDOUT:
153assign
154subshell
155subshell
156dparen
157dbracket
158ok
159## END
160
161
162#### trap ERR does not run in errexit situations
163
164trap 'echo line=$LINENO' ERR
165
166if false; then
167 echo if
168fi
169
170while false; do
171 echo while
172done
173
174until false; do
175 echo until
176 break
177done
178
179false || false || false
180
181false && false && false
182
183false; false; false
184
185echo ok
186
187## STDOUT:
188until
189line=16
190line=20
191line=20
192line=20
193ok
194## END
195
196
197#### trap ERR doesn't run in subprograms - subshell, command sub, async
198
199trap 'echo line=$LINENO' ERR
200
201( false; echo subshell )
202
203x=$( false; echo command sub )
204
205false & wait
206
207{ false; echo async; } & wait
208
209false
210echo ok
211
212## STDOUT:
213subshell
214async
215line=11
216ok
217## END
218
219#### set -o errtrace: trap ERR runs in subprograms
220
221case $SH in mksh) exit ;; esac
222
223set -o errtrace
224trap 'echo line=$LINENO' ERR
225
226( false; echo subshell )
227
228x=$( false; echo command sub )
229
230false & wait
231
232{ false; echo async; } & wait
233
234false
235echo ok
236
237## STDOUT:
238line=6
239subshell
240line=12
241async
242line=14
243ok
244## END
245
246# ash doesn't reject errtrace, but doesn't implement it
247## BUG ash STDOUT:
248subshell
249async
250line=14
251ok
252## END
253
254## N-I mksh STDOUT:
255## END
256
257
258#### trap ERR not active in shell functions in (bash behavior)
259
260trap 'echo line=$LINENO' ERR
261
262f() {
263 false
264 true
265}
266
267f
268
269## STDOUT:
270## END
271
272## N-I mksh STDOUT:
273line=4
274## END
275
276#### set -o errtrace - trap ERR runs in shell functions
277
278trap 'echo line=$LINENO' ERR
279
280passing() {
281 false # line 4
282 true
283}
284
285failing() {
286 true
287 false
288}
289
290passing
291failing
292
293set -o errtrace
294
295echo 'now with errtrace'
296passing
297failing
298
299echo ok
300
301## STDOUT:
302line=14
303now with errtrace
304line=4
305line=10
306line=20
307ok
308## END
309
310## BUG mksh status: 1
311## BUG mksh STDOUT:
312line=4
313line=10
314## END
315
316#### trap ERR with "atoms": assignment (( [[
317
318trap 'echo line=$LINENO' ERR
319
320x=$(false)
321
322[[ a == b ]]
323
324(( 0 ))
325echo ok
326
327## STDOUT:
328line=3
329line=5
330line=7
331ok
332## END
333
334## BUG mksh STDOUT:
335line=3
336line=3
337line=7
338ok
339## END
340
341
342#### trap ERR with for, case, { }
343
344trap 'echo line=$LINENO' ERR
345
346for y in 1 2; do
347 false
348done
349
350case x in
351 x) false ;;
352 *) false ;;
353esac
354
355{ false; false; }
356echo ok
357
358## STDOUT:
359line=4
360line=4
361line=8
362line=12
363line=12
364ok
365## END
366
367#### trap ERR with redirect
368
369trap 'echo line=$LINENO' ERR
370
371false
372
373{ false
374 true
375} > /zz # error
376echo ok
377
378## STDOUT:
379line=3
380line=7
381ok
382## END
383
384# doesn't update line for redirect
385
386## BUG bash/mksh STDOUT:
387line=3
388line=3
389ok
390## END
391
392## BUG ash STDOUT:
393line=3
394ok
395## END
396
397
398#### trap ERR with YSH proc
399
400case $SH in bash|mksh|ash) exit ;; esac
401
402# seems the same
403
404shopt -s ysh:upgrade
405
406proc handler {
407 echo err
408}
409
410if test -f /nope { echo file exists }
411
412trap handler ERR
413
414if test -f /nope { echo file exists }
415
416false || true # not run for the first part here
417false
418
419## status: 1
420## STDOUT:
421err
422## END
423
424## N-I bash/mksh/ash status: 0
425## N-I bash/mksh/ash STDOUT:
426## END
427
428#### trap ERR
429err() {
430 echo "err [$@] $?"
431}
432trap 'err x y' ERR
433
434echo A
435
436false
437echo B
438
439( exit 42 )
440echo C
441
442trap - ERR # disable trap
443
444false
445echo D
446
447trap 'echo after errexit $?' ERR
448
449set -o errexit
450
451( exit 99 )
452echo E
453
454## status: 99
455## STDOUT:
456A
457err [x y] 1
458B
459err [x y] 42
460C
461D
462after errexit 99
463## END
464## N-I dash STDOUT:
465A
466B
467C
468D
469## END
470
471#### trap ERR and pipelines (lastpipe and PIPESTATUS difference)
472case $SH in ash) exit ;; esac
473
474err() {
475 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
476}
477trap 'err' ERR
478
479echo A
480
481false
482
483# succeeds
484echo B | grep B
485
486# fails
487echo C | grep zzz
488
489echo D | grep zzz | cat
490
491set -o pipefail
492echo E | grep zzz | cat
493
494trap - ERR # disable trap
495
496echo F | grep zz
497echo ok
498
499## STDOUT:
500A
501err [] status=1 [1]
502B
503err [] status=1 [0 1]
504err [] status=1 [0 1 0]
505ok
506## END
507
508# lastpipe semantics mean we get another call!
509# also we don't set PIPESTATUS unless we get a pipeline
510
511## OK osh STDOUT:
512A
513err [] status=1 []
514B
515err [] status=1 [0 0]
516err [] status=1 [0 1]
517err [] status=1 [0 1 0]
518ok
519## END
520
521## N-I ash STDOUT:
522## END
523
524#### error in trap ERR (recursive)
525case $SH in dash) exit ;; esac
526
527err() {
528 echo err status $?
529 false
530 ( exit 2 ) # not recursively triggered
531 echo err 2
532}
533trap 'err' ERR
534
535echo A
536false
537echo B
538
539# Try it with errexit
540set -e
541false
542echo C
543
544## status: 1
545## STDOUT:
546A
547err status 1
548err 2
549B
550err status 1
551## END
552## N-I dash STDOUT:
553## END
554