1 ## compare_shells: dash bash mksh ash
2 ## oils_failures_allowed: 0
3
4 #### errexit aborts early
5 set -o errexit
6 false
7 echo done
8 ## stdout-json: ""
9 ## status: 1
10
11 #### errexit for nonexistent command
12 set -o errexit
13 nonexistent__ZZ
14 echo done
15 ## stdout-json: ""
16 ## status: 127
17
18 #### errexit aborts early on pipeline
19 set -o errexit
20 echo hi | grep nonexistent
21 echo two
22 ## stdout-json: ""
23 ## status: 1
24
25 #### errexit with { }
26 # This aborts because it's not part of an if statement.
27 set -o errexit
28 { echo one; false; echo two; }
29 ## stdout: one
30 ## status: 1
31
32 #### errexit with if and { }
33 set -o errexit
34 if { echo one; false; echo two; }; then
35 echo three
36 fi
37 echo four
38 ## status: 0
39 ## STDOUT:
40 one
41 two
42 three
43 four
44 ## END
45
46 #### errexit with ||
47 set -o errexit
48 echo hi | grep nonexistent || echo ok
49 ## stdout: ok
50 ## status: 0
51
52 #### errexit with &&
53 set -o errexit
54 echo ok && echo hi | grep nonexistent
55 ## stdout: ok
56 ## status: 1
57
58 #### errexit test && -- from gen-module-init
59 set -o errexit
60 test "$mod" = readline && echo "#endif"
61 echo status=$?
62 ## stdout: status=1
63
64 #### errexit test && and fail
65 set -o errexit
66 test -n X && false
67 echo status=$?
68 ## stdout-json: ""
69 ## status: 1
70
71 #### errexit and loop
72 set -o errexit
73 for x in 1 2 3; do
74 test $x = 2 && echo "hi $x"
75 done
76 ## stdout: hi 2
77 ## status: 1
78
79 #### errexit and brace group { }
80 set -o errexit
81 { test no = yes && echo hi; }
82 echo status=$?
83 ## stdout: status=1
84
85 #### errexit and time { }
86 set -o errexit
87 time false
88 echo status=$?
89 ## status: 1
90
91 #### errexit with !
92 set -o errexit
93 echo one
94 ! true
95 echo two
96 ! false
97 echo three
98 ## STDOUT:
99 one
100 two
101 three
102 ## END
103
104 #### errexit with ! and ;
105 # AST has extra Sentence nodes; there was a REGRESSION here.
106 set -o errexit; echo one; ! true; echo two; ! false; echo three
107 ## STDOUT:
108 one
109 two
110 three
111 ## END
112
113 #### errexit with while/until
114 set -o errexit
115 while false; do
116 echo ok
117 done
118 until false; do
119 echo ok # do this once then exit loop
120 break
121 done
122 ## stdout: ok
123 ## status: 0
124
125 #### errexit with (( ))
126 # from http://mywiki.wooledge.org/BashFAQ/105, this changed between versions.
127 # ash says that 'i++' is not found, but it doesn't exit. I guess this is the
128 # subshell problem?
129 set -o errexit
130 i=0
131 (( i++ ))
132 echo done
133 ## stdout-json: ""
134 ## status: 1
135 ## N-I dash/ash status: 127
136 ## N-I dash/ash stdout-json: ""
137
138 #### errexit with subshell
139 set -o errexit
140 ( echo one; false; echo two; )
141 echo three
142 ## status: 1
143 ## STDOUT:
144 one
145 ## END
146
147 #### set -o errexit while it's being ignored (moot with strict_errexit)
148 set -o errexit
149 # osh aborts early here
150 if { echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; }; then
151 echo 5;
152 fi
153 echo 6
154 false # this is the one that makes shells fail
155 echo 7
156 ## status: 1
157 ## STDOUT:
158 1
159 2
160 3
161 4
162 5
163 6
164 ## END
165
166 #### set +o errexit while it's being ignored (moot with strict_errexit)
167 set -o errexit
168 if { echo 1; false; echo 2; set +o errexit; echo 3; false; echo 4; }; then
169 echo 5;
170 fi
171 echo 6
172 false # does NOT fail, because we restored it.
173 echo 7
174 ## STDOUT:
175 1
176 2
177 3
178 4
179 5
180 6
181 7
182 ## END
183
184 #### set +o errexit with 2 levels of ignored
185 set -o errexit
186 if { echo 1; ! set +o errexit; echo 2; }; then
187 echo 3
188 fi
189 echo 6
190 false
191 echo 7
192
193 ## STDOUT:
194 1
195 2
196 3
197 6
198 7
199 ## END
200
201 #### setting errexit in a subshell works but doesn't affect parent shell
202 ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; )
203 echo 5
204 false
205 echo 6
206 ## STDOUT:
207 1
208 2
209 3
210 5
211 6
212 ## END
213
214 #### set errexit while it's ignored in a subshell (moot with strict_errexit)
215 set -o errexit
216 if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
217 echo 5;
218 fi
219 echo 6 # This is executed because the subshell just returns false
220 false
221 echo 7
222 ## status: 1
223 ## STDOUT:
224 1
225 2
226 3
227 4
228 5
229 6
230 ## END
231
232 #### shopt -s strict:all || true while errexit is on
233 set -o errexit
234 shopt -s strict:all || true
235 echo one
236 false # fail
237 echo two
238 ## status: 1
239 ## STDOUT:
240 one
241 ## END
242
243 #### errexit double guard
244 # OSH bug fix. ErrExit needs a counter, not a boolean.
245 set -o errexit
246 if { ! false; false; true; } then
247 echo true
248 fi
249 false
250 echo done
251 ## status: 1
252 ## STDOUT:
253 true
254 ## END
255
256 #### background processes respect errexit
257 set -o errexit
258 { echo one; false; echo two; exit 42; } &
259 wait $!
260 ## status: 1
261 ## STDOUT:
262 one
263 ## END
264
265 #### pipeline process respects errexit
266 set -o errexit
267 # It is respected here.
268 { echo one; false; echo two; } | cat
269
270 # Also respected here.
271 { echo three; echo four; } | while read line; do
272 echo "[$line]"
273 false
274 done
275 echo four
276 ## status: 1
277 ## STDOUT:
278 one
279 [three]
280 ## END
281
282 #### simple command / assign - redir failure DOES respect errexit
283
284 $SH -c '
285 set -o errexit
286 true > /
287 echo builtin status=$?
288 '
289 echo status=$?
290
291 $SH -c '
292 set -o errexit
293 /bin/true > /
294 echo extern status=$?
295 '
296 echo status=$?
297
298 $SH -c '
299 set -o errexit
300 assign=foo > /
301 echo assign status=$?
302 '
303 echo status=$?
304
305 ## STDOUT:
306 status=1
307 status=1
308 status=1
309 ## END
310 ## OK dash STDOUT:
311 status=2
312 status=2
313 status=2
314 ## END
315
316 #### simple command that's an alias -- redir failure NOT checked
317
318 $SH -c '
319 shopt -s expand_aliases
320
321 set -o errexit
322 alias zz="{ echo 1; echo 2; }"
323 zz > /
324 echo alias status=$?
325 '
326 echo status=$?
327
328 ## STDOUT:
329 alias status=1
330 status=0
331 ## END
332
333 ## OK dash STDOUT:
334 alias status=2
335 status=0
336 ## END
337
338 ## BUG mksh STDOUT:
339 status=1
340 ## END
341
342 #### bash atoms [[ (( - redir failure does NOT respect errexit (unless redir_errexit)
343 case $SH in dash) exit ;; esac
344
345 $SH -c '
346 set -o errexit
347 [[ x = x ]] > /
348 echo dbracket status=$?
349 '
350 echo status=$?
351
352 $SH -c '
353 set -o errexit
354 (( 42 )) > /
355 echo dparen status=$?
356 '
357 echo status=$?
358
359 ## STDOUT:
360 dbracket status=1
361 status=0
362 dparen status=1
363 status=0
364 ## END
365
366 # mksh checks errors!
367
368 ## OK mksh STDOUT:
369 status=1
370 status=1
371 ## END
372
373 ## OK ash STDOUT:
374 status=1
375 status=2
376 ## END
377
378 ## N-I dash STDOUT:
379 ## END
380
381
382 #### brace group - redir failure does NOT respect errexit
383 # case from
384 # https://lists.gnu.org/archive/html/bug-bash/2020-05/msg00066.html
385
386 set -o errexit
387
388 { cat ; } < not_exist.txt
389
390 echo status=$?
391 echo 'should not get here'
392
393 ## STDOUT:
394 status=1
395 should not get here
396 ## END
397
398 ## OK dash STDOUT:
399 status=2
400 should not get here
401 ## END
402
403 ## BUG mksh status: 1
404 ## BUG mksh STDOUT:
405 ## END
406
407 #### while loop - redirect failure does NOT respect errexit
408 # case from
409 # https://lists.gnu.org/archive/html/bug-bash/2020-05/msg00066.html
410
411 set -o errexit
412
413 while read line; do
414 echo $line
415 done < not_exist.txt
416
417 echo status=$?
418 echo 'should not get here'
419
420 ## STDOUT:
421 status=1
422 should not get here
423 ## END
424
425 ## OK dash STDOUT:
426 status=2
427 should not get here
428 ## END
429
430 ## BUG mksh status: 1
431 ## BUG mksh STDOUT:
432 ## END
433
434 #### set -e enabled in function (regression)
435 foo() {
436 set -e
437 false
438 echo "should be executed"
439 }
440 #foo && true
441 #foo || true
442
443 if foo; then
444 true
445 fi
446
447 echo "should be executed"
448 ## STDOUT:
449 should be executed
450 should be executed
451 ## END
452
453 #### set -e in function #2
454 foo() {
455 set -e
456 false
457 echo "should be executed"
458 }
459 ! foo
460
461 echo "should be executed"
462 ## BUG bash stdout-json: ""
463 ## BUG bash status: 1
464 ## STDOUT:
465 should be executed
466 should be executed
467 ## END
468
469
470 #### Command sub exit code is lost
471 echo ft $(false) $(true)
472 echo status=$?
473
474 set -o errexit
475 shopt -s inherit_errexit || true
476
477 # This changes it
478 #shopt -s command_sub_errexit || true
479
480 echo f $(date %x)
481 echo status=$?
482
483 # compare with
484 # x=$(date %x) # FAILS
485 # local x=$(date %x) # does NOT fail
486
487 echo ft $(false) $(true)
488 echo status=$?
489
490 ## STDOUT:
491 ft
492 status=0
493 f
494 status=0
495 ft
496 status=0
497 ## END
498