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 | #### 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 checked
|
319 |
|
320 | # bash 5.2 fixed bash 4.4 bug: this is now checked
|
321 |
|
322 | $SH -c '
|
323 | shopt -s expand_aliases
|
324 |
|
325 | set -o errexit
|
326 | alias zz="{ echo 1; echo 2; }"
|
327 | zz > /
|
328 | echo alias status=$?
|
329 | '
|
330 | echo status=$?
|
331 |
|
332 | ## STDOUT:
|
333 | status=1
|
334 | ## END
|
335 |
|
336 | ## BUG dash STDOUT:
|
337 | alias status=2
|
338 | status=0
|
339 | ## END
|
340 |
|
341 | ## BUG ash STDOUT:
|
342 | alias status=1
|
343 | status=0
|
344 | ## END
|
345 |
|
346 | #### bash atoms [[ (( - redir failure checked
|
347 |
|
348 | # bash 5.2 fixed bash 4.4 bug: this is now checked
|
349 |
|
350 | case $SH in dash) exit ;; esac
|
351 |
|
352 | $SH -c '
|
353 | set -o errexit
|
354 | [[ x = x ]] > /
|
355 | echo dbracket status=$?
|
356 | '
|
357 | echo status=$?
|
358 |
|
359 | $SH -c '
|
360 | set -o errexit
|
361 | (( 42 )) > /
|
362 | echo dparen status=$?
|
363 | '
|
364 | echo status=$?
|
365 |
|
366 | ## STDOUT:
|
367 | status=1
|
368 | status=1
|
369 | ## END
|
370 |
|
371 | ## OK ash STDOUT:
|
372 | status=1
|
373 | status=2
|
374 | ## END
|
375 |
|
376 | ## N-I dash STDOUT:
|
377 | ## END
|
378 |
|
379 |
|
380 | #### brace group - redir failure checked
|
381 |
|
382 | # bash 5.2 fixed bash 4.4 bug: this is now checked
|
383 |
|
384 | # case from
|
385 | # https://lists.gnu.org/archive/html/bug-bash/2020-05/msg00066.html
|
386 |
|
387 | set -o errexit
|
388 |
|
389 | { cat ; } < not_exist.txt
|
390 |
|
391 | echo status=$?
|
392 | echo 'should not get here'
|
393 |
|
394 | ## status: 1
|
395 | ## STDOUT:
|
396 | ## END
|
397 |
|
398 | ## BUG dash status: 0
|
399 | ## BUG dash STDOUT:
|
400 | status=2
|
401 | should not get here
|
402 | ## END
|
403 |
|
404 | ## BUG ash status: 0
|
405 | ## BUG ash STDOUT:
|
406 | status=1
|
407 | should not get here
|
408 | ## END
|
409 |
|
410 |
|
411 | #### while loop - redirect failure checked
|
412 |
|
413 | # bash 5.2 fixed bash 4.4 bug: this is now checked
|
414 |
|
415 | # case from
|
416 | # https://lists.gnu.org/archive/html/bug-bash/2020-05/msg00066.html
|
417 |
|
418 | set -o errexit
|
419 |
|
420 | while read line; do
|
421 | echo $line
|
422 | done < not_exist.txt
|
423 |
|
424 | echo status=$?
|
425 | echo 'should not get here'
|
426 |
|
427 | ## status: 1
|
428 | ## STDOUT:
|
429 | ## END
|
430 |
|
431 | ## BUG dash status: 0
|
432 | ## BUG dash STDOUT:
|
433 | status=2
|
434 | should not get here
|
435 | ## END
|
436 |
|
437 | ## BUG ash status: 0
|
438 | ## BUG ash STDOUT:
|
439 | status=1
|
440 | should not get here
|
441 | ## END
|
442 |
|
443 |
|
444 | #### set -e enabled in function (regression)
|
445 | foo() {
|
446 | set -e
|
447 | false
|
448 | echo "should be executed"
|
449 | }
|
450 | #foo && true
|
451 | #foo || true
|
452 |
|
453 | if foo; then
|
454 | true
|
455 | fi
|
456 |
|
457 | echo "should be executed"
|
458 | ## STDOUT:
|
459 | should be executed
|
460 | should be executed
|
461 | ## END
|
462 |
|
463 | #### set -e in function #2
|
464 | foo() {
|
465 | set -e
|
466 | false
|
467 | echo "should be executed"
|
468 | }
|
469 | ! foo
|
470 |
|
471 | echo "should be executed"
|
472 | ## BUG bash stdout-json: ""
|
473 | ## BUG bash status: 1
|
474 | ## STDOUT:
|
475 | should be executed
|
476 | should be executed
|
477 | ## END
|
478 |
|
479 |
|
480 | #### Command sub exit code is lost
|
481 | echo ft $(false) $(true)
|
482 | echo status=$?
|
483 |
|
484 | set -o errexit
|
485 | shopt -s inherit_errexit || true
|
486 |
|
487 | # This changes it
|
488 | #shopt -s command_sub_errexit || true
|
489 |
|
490 | echo f $(date %x)
|
491 | echo status=$?
|
492 |
|
493 | # compare with
|
494 | # x=$(date %x) # FAILS
|
495 | # local x=$(date %x) # does NOT fail
|
496 |
|
497 | echo ft $(false) $(true)
|
498 | echo status=$?
|
499 |
|
500 | ## STDOUT:
|
501 | ft
|
502 | status=0
|
503 | f
|
504 | status=0
|
505 | ft
|
506 | status=0
|
507 | ## END
|
508 |
|