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