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