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