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

370 lines, 187 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#### trap ERR does not run in errexit situations
85
86trap 'echo line=$LINENO' ERR
87
88if false; then
89 echo if
90fi
91
92while false; do
93 echo while
94done
95
96until false; do
97 echo until
98 break
99done
100
101false || false || false
102
103false && false && false
104
105false; false; false
106
107echo ok
108
109## STDOUT:
110until
111line=16
112line=20
113line=20
114line=20
115ok
116## END
117
118#### trap ERR pipeline (also errexit)
119
120# mksh and bash have different line numbers in this case
121#trap 'echo line=$LINENO' ERR
122trap 'echo line=$LINENO' ERR
123
124# it's run for the last 'false'
125false | false | false
126
127{ echo pipeline; false; } | false | false
128
129# it's never run here
130! true
131! false
132
133## STDOUT:
134line=3
135line=5
136## END
137
138## BUG mksh/ash STDOUT:
139line=1
140line=1
141## END
142
143#### trap ERR subprogram - subshell, command sub, async
144
145trap 'echo line=$LINENO' ERR
146
147( false; echo subshell )
148
149x=$( false; echo command sub )
150
151false & wait
152
153{ false; echo async; } & wait
154
155false
156echo ok
157
158## STDOUT:
159subshell
160async
161line=11
162ok
163## END
164
165#### trap ERR not active in shell functions in (bash behavior)
166
167trap 'echo line=$LINENO' ERR
168
169f() {
170 false
171 true
172}
173
174f
175
176## STDOUT:
177## END
178
179## N-I mksh STDOUT:
180line=4
181## END
182
183#### trap ERR shell function - with errtrace
184
185trap 'echo line=$LINENO' ERR
186
187passing() {
188 false # line 4
189 true
190}
191
192failing() {
193 true
194 false
195}
196
197passing
198failing
199
200set -o errtrace
201
202echo 'now with errtrace'
203passing
204failing
205
206echo ok
207
208## STDOUT:
209line=14
210now with errtrace
211line=4
212line=10
213line=20
214ok
215## END
216
217## BUG mksh status: 1
218## BUG mksh STDOUT:
219line=4
220line=10
221## END
222
223
224#### trap ERR with YSH proc
225
226case $SH in bash|mksh|ash) exit ;; esac
227
228# seems the same
229
230shopt -s ysh:upgrade
231
232proc abc { echo abc }
233if test -f /nope { echo file exists }
234trap abc ERR
235if test -f /nope { echo file exists }
236
237## STDOUT:
238abc
239## END
240
241## N-I bash/mksh/ash STDOUT:
242## END
243
244#### trap ERR
245err() {
246 echo "err [$@] $?"
247}
248trap 'err x y' ERR
249
250echo A
251
252false
253echo B
254
255( exit 42 )
256echo C
257
258trap - ERR # disable trap
259
260false
261echo D
262
263trap 'echo after errexit $?' ERR
264
265set -o errexit
266
267( exit 99 )
268echo E
269
270## status: 99
271## STDOUT:
272A
273err [x y] 1
274B
275err [x y] 42
276C
277D
278after errexit 99
279## END
280## N-I dash STDOUT:
281A
282B
283C
284D
285## END
286
287#### trap ERR and pipelines (lastpipe and PIPESTATUS difference)
288case $SH in ash) exit ;; esac
289
290err() {
291 echo "err [$@] status=$? [${PIPESTATUS[@]}]"
292}
293trap 'err' ERR
294
295echo A
296
297false
298
299# succeeds
300echo B | grep B
301
302# fails
303echo C | grep zzz
304
305echo D | grep zzz | cat
306
307set -o pipefail
308echo E | grep zzz | cat
309
310trap - ERR # disable trap
311
312echo F | grep zz
313echo ok
314
315## STDOUT:
316A
317err [] status=1 [1]
318B
319err [] status=1 [0 1]
320err [] status=1 [0 1 0]
321ok
322## END
323
324# lastpipe semantics mean we get another call!
325# also we don't set PIPESTATUS unless we get a pipeline
326
327## OK osh STDOUT:
328A
329err [] status=1 []
330B
331err [] status=1 [0 0]
332err [] status=1 [0 1]
333err [] status=1 [0 1 0]
334ok
335## END
336
337## N-I ash STDOUT:
338## END
339
340#### error in trap ERR (recursive)
341case $SH in dash) exit ;; esac
342
343err() {
344 echo err status $?
345 false
346 ( exit 2 ) # not recursively triggered
347 echo err 2
348}
349trap 'err' ERR
350
351echo A
352false
353echo B
354
355# Try it with errexit
356set -e
357false
358echo C
359
360## status: 1
361## STDOUT:
362A
363err status 1
364err 2
365B
366err status 1
367## END
368## N-I dash STDOUT:
369## END
370