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

457 lines, 231 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 does not run in errexit situations
128
129trap 'echo line=$LINENO' ERR
130
131if false; then
132 echo if
133fi
134
135while false; do
136 echo while
137done
138
139until false; do
140 echo until
141 break
142done
143
144false || false || false
145
146false && false && false
147
148false; false; false
149
150echo ok
151
152## STDOUT:
153until
154line=16
155line=20
156line=20
157line=20
158ok
159## END
160
161
162#### trap ERR subprogram - subshell, command sub, async
163
164trap 'echo line=$LINENO' ERR
165
166( false; echo subshell )
167
168x=$( false; echo command sub )
169
170false & wait
171
172{ false; echo async; } & wait
173
174false
175echo ok
176
177## STDOUT:
178subshell
179async
180line=11
181ok
182## END
183
184#### trap ERR not active in shell functions in (bash behavior)
185
186trap 'echo line=$LINENO' ERR
187
188f() {
189 false
190 true
191}
192
193f
194
195## STDOUT:
196## END
197
198## N-I mksh STDOUT:
199line=4
200## END
201
202#### trap ERR shell function - with errtrace
203
204trap 'echo line=$LINENO' ERR
205
206passing() {
207 false # line 4
208 true
209}
210
211failing() {
212 true
213 false
214}
215
216passing
217failing
218
219set -o errtrace
220
221echo 'now with errtrace'
222passing
223failing
224
225echo ok
226
227## STDOUT:
228line=14
229now with errtrace
230line=4
231line=10
232line=20
233ok
234## END
235
236## BUG mksh status: 1
237## BUG mksh STDOUT:
238line=4
239line=10
240## END
241
242#### trap ERR with assignment, for, case, { }
243
244trap 'echo line=$LINENO' ERR
245
246x=$(false)
247
248for y in 1 2; do
249 false
250done
251
252case x in
253 x) false ;;
254 *) false ;;
255esac
256
257{ false; false; }
258echo ok
259
260## STDOUT:
261line=3
262line=6
263line=6
264line=10
265line=14
266line=14
267ok
268## END
269
270#### trap ERR with redirect
271
272trap 'echo line=$LINENO' ERR
273
274false
275
276{ false
277 true
278} > /zz # error
279echo ok
280
281## STDOUT:
282line=3
283line=7
284ok
285## END
286
287# doesn't update line for redirect
288
289## BUG bash/mksh STDOUT:
290line=3
291line=3
292ok
293## END
294
295## BUG ash STDOUT:
296line=3
297ok
298## END
299
300
301#### trap ERR with YSH proc
302
303case $SH in bash|mksh|ash) exit ;; esac
304
305# seems the same
306
307shopt -s ysh:upgrade
308
309proc handler {
310 echo err
311}
312
313if test -f /nope { echo file exists }
314
315trap handler ERR
316
317if test -f /nope { echo file exists }
318
319false || true # not run for the first part here
320false
321
322## status: 1
323## STDOUT:
324err
325## END
326
327## N-I bash/mksh/ash status: 0
328## N-I bash/mksh/ash STDOUT:
329## END
330
331#### trap ERR
332err() {
333 echo "err [$@] $?"
334}
335trap 'err x y' ERR
336
337echo A
338
339false
340echo B
341
342( exit 42 )
343echo C
344
345trap - ERR # disable trap
346
347false
348echo D
349
350trap 'echo after errexit $?' ERR
351
352set -o errexit
353
354( exit 99 )
355echo E
356
357## status: 99
358## STDOUT:
359A
360err [x y] 1
361B
362err [x y] 42
363C
364D
365after errexit 99
366## END
367## N-I dash STDOUT:
368A
369B
370C
371D
372## END
373
374#### trap ERR and pipelines (lastpipe and PIPESTATUS difference)
375case $SH in ash) exit ;; esac
376
377err() {
378 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
379}
380trap 'err' ERR
381
382echo A
383
384false
385
386# succeeds
387echo B | grep B
388
389# fails
390echo C | grep zzz
391
392echo D | grep zzz | cat
393
394set -o pipefail
395echo E | grep zzz | cat
396
397trap - ERR # disable trap
398
399echo F | grep zz
400echo ok
401
402## STDOUT:
403A
404err [] status=1 [1]
405B
406err [] status=1 [0 1]
407err [] status=1 [0 1 0]
408ok
409## END
410
411# lastpipe semantics mean we get another call!
412# also we don't set PIPESTATUS unless we get a pipeline
413
414## OK osh STDOUT:
415A
416err [] status=1 []
417B
418err [] status=1 [0 0]
419err [] status=1 [0 1]
420err [] status=1 [0 1 0]
421ok
422## END
423
424## N-I ash STDOUT:
425## END
426
427#### error in trap ERR (recursive)
428case $SH in dash) exit ;; esac
429
430err() {
431 echo err status $?
432 false
433 ( exit 2 ) # not recursively triggered
434 echo err 2
435}
436trap 'err' ERR
437
438echo A
439false
440echo B
441
442# Try it with errexit
443set -e
444false
445echo C
446
447## status: 1
448## STDOUT:
449A
450err status 1
451err 2
452B
453err status 1
454## END
455## N-I dash STDOUT:
456## END
457