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

579 lines, 295 significant
1## oils_failures_allowed: 2
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
132trap 'echo dparen' ERR
133(( 0 )) | (( 0 )) | (( 0 ))
134
135trap 'echo dbracket' ERR
136[[ a = b ]] | [[ a = b ]] | [[ a = b ]]
137
138# bash anomaly - it gets printed twice?
139trap 'echo subshell' ERR
140(false) | (false) | (false) | (false)
141
142# same bug
143trap 'echo subshell2' ERR
144(false) | (false) | (false) | (false; false)
145
146trap 'echo group' ERR
147{ false; } | { false; } | { false; }
148
149echo ok
150
151## STDOUT:
152assign
153dparen
154dbracket
155subshell
156subshell2
157group
158ok
159## END
160
161## BUG bash STDOUT:
162assign
163dparen
164dbracket
165subshell
166subshell
167subshell2
168subshell2
169group
170ok
171## END
172
173
174#### Pipeline group quirk
175
176# Oh this is because it's run for the PIPELINE, not for the last thing! Hmmm
177
178trap 'echo group2' ERR
179{ false; } | { false; } | { false; false; }
180
181echo ok
182
183## STDOUT:
184group2
185ok
186## END
187
188#### trap ERR does not run in errexit situations
189
190trap 'echo line=$LINENO' ERR
191
192if false; then
193 echo if
194fi
195
196while false; do
197 echo while
198done
199
200until false; do
201 echo until
202 break
203done
204
205false || false || false
206
207false && false && false
208
209false; false; false
210
211echo ok
212
213## STDOUT:
214until
215line=16
216line=20
217line=20
218line=20
219ok
220## END
221
222
223#### trap ERR doesn't run in subprograms - subshell, command sub, async
224
225trap 'echo line=$LINENO' ERR
226
227( false; echo subshell )
228
229x=$( false; echo command sub )
230
231false & wait
232
233{ false; echo async; } & wait
234
235false
236echo ok
237
238## STDOUT:
239subshell
240async
241line=11
242ok
243## END
244
245#### set -o errtrace: trap ERR runs in subprograms
246
247case $SH in mksh) exit ;; esac
248
249set -o errtrace
250trap 'echo line=$LINENO' ERR
251
252( false; echo subshell )
253
254x=$( false; echo command sub )
255
256false & wait
257
258{ false; echo async; } & wait
259
260false
261echo ok
262
263## STDOUT:
264line=6
265subshell
266line=12
267async
268line=14
269ok
270## END
271
272# ash doesn't reject errtrace, but doesn't implement it
273## BUG ash STDOUT:
274subshell
275async
276line=14
277ok
278## END
279
280## N-I mksh STDOUT:
281## END
282
283
284#### trap ERR not active in shell functions in (bash behavior)
285
286trap 'echo line=$LINENO' ERR
287
288f() {
289 false
290 true
291}
292
293f
294
295## STDOUT:
296## END
297
298## N-I mksh STDOUT:
299line=4
300## END
301
302#### set -o errtrace - trap ERR runs in shell functions
303
304trap 'echo line=$LINENO' ERR
305
306passing() {
307 false # line 4
308 true
309}
310
311failing() {
312 true
313 false
314}
315
316passing
317failing
318
319set -o errtrace
320
321echo 'now with errtrace'
322passing
323failing
324
325echo ok
326
327## STDOUT:
328line=14
329now with errtrace
330line=4
331line=10
332line=20
333ok
334## END
335
336## BUG mksh status: 1
337## BUG mksh STDOUT:
338line=4
339line=10
340## END
341
342#### trap ERR with "atoms": assignment (( [[
343
344trap 'echo line=$LINENO' ERR
345
346x=$(false)
347
348[[ a == b ]]
349
350(( 0 ))
351echo ok
352
353## STDOUT:
354line=3
355line=5
356line=7
357ok
358## END
359
360## BUG mksh STDOUT:
361line=3
362line=3
363line=7
364ok
365## END
366
367
368#### trap ERR with for, case, { }
369
370trap 'echo line=$LINENO' ERR
371
372for y in 1 2; do
373 false
374done
375
376case x in
377 x) false ;;
378 *) false ;;
379esac
380
381{ false; false; false; }
382echo ok
383
384## STDOUT:
385line=4
386line=4
387line=8
388line=12
389line=12
390line=12
391ok
392## END
393
394#### trap ERR with redirect
395
396trap 'echo line=$LINENO' ERR
397
398false
399
400{ false
401 true
402} > /zz # error
403echo ok
404
405## STDOUT:
406line=3
407line=7
408ok
409## END
410
411# doesn't update line for redirect
412
413## BUG bash/mksh STDOUT:
414line=3
415line=3
416ok
417## END
418
419## BUG ash STDOUT:
420line=3
421ok
422## END
423
424
425#### trap ERR with YSH proc
426
427case $SH in bash|mksh|ash) exit ;; esac
428
429# seems the same
430
431shopt -s ysh:upgrade
432
433proc handler {
434 echo err
435}
436
437if test -f /nope { echo file exists }
438
439trap handler ERR
440
441if test -f /nope { echo file exists }
442
443false || true # not run for the first part here
444false
445
446## status: 1
447## STDOUT:
448err
449## END
450
451## N-I bash/mksh/ash status: 0
452## N-I bash/mksh/ash STDOUT:
453## END
454
455#### trap ERR
456err() {
457 echo "err [$@] $?"
458}
459trap 'err x y' ERR
460
461echo A
462
463false
464echo B
465
466( exit 42 )
467echo C
468
469trap - ERR # disable trap
470
471false
472echo D
473
474trap 'echo after errexit $?' ERR
475
476set -o errexit
477
478( exit 99 )
479echo E
480
481## status: 99
482## STDOUT:
483A
484err [x y] 1
485B
486err [x y] 42
487C
488D
489after errexit 99
490## END
491## N-I dash STDOUT:
492A
493B
494C
495D
496## END
497
498#### trap ERR and pipelines - PIPESTATUS difference
499case $SH in ash) exit ;; esac
500
501err() {
502 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
503}
504trap 'err' ERR
505
506echo A
507
508false
509
510# succeeds
511echo B | grep B
512
513# fails
514echo C | grep zzz
515
516echo D | grep zzz | cat
517
518set -o pipefail
519echo E | grep zzz | cat
520
521trap - ERR # disable trap
522
523echo F | grep zz
524echo ok
525
526## STDOUT:
527A
528err [] status=1 [1]
529B
530err [] status=1 [0 1]
531err [] status=1 [0 1 0]
532ok
533## END
534
535# we don't set PIPESTATUS unless we get a pipeline
536
537## OK osh STDOUT:
538A
539err [] status=1 []
540B
541err [] status=1 [0 1]
542err [] status=1 [0 1 0]
543ok
544## END
545
546## N-I ash STDOUT:
547## END
548
549#### error in trap ERR (recursive)
550case $SH in dash) exit ;; esac
551
552err() {
553 echo err status $?
554 false
555 ( exit 2 ) # not recursively triggered
556 echo err 2
557}
558trap 'err' ERR
559
560echo A
561false
562echo B
563
564# Try it with errexit
565set -e
566false
567echo C
568
569## status: 1
570## STDOUT:
571A
572err status 1
573err 2
574B
575err status 1
576## END
577## N-I dash STDOUT:
578## END
579