OILS / spec / errexit.test.sh View on Github | oilshell.org

532 lines, 249 significant
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
7set -o errexit
8false
9echo done
10## stdout-json: ""
11## status: 1
12
13#### errexit for nonexistent command
14set -o errexit
15nonexistent__ZZ
16echo done
17## stdout-json: ""
18## status: 127
19
20#### errexit aborts early on pipeline
21set -o errexit
22echo hi | grep nonexistent
23echo two
24## stdout-json: ""
25## status: 1
26
27#### errexit with { }
28# This aborts because it's not part of an if statement.
29set -o errexit
30{ echo one; false; echo two; }
31## stdout: one
32## status: 1
33
34#### errexit with if and { }
35set -o errexit
36if { echo one; false; echo two; }; then
37 echo three
38fi
39echo four
40## status: 0
41## STDOUT:
42one
43two
44three
45four
46## END
47
48#### errexit with ||
49set -o errexit
50echo hi | grep nonexistent || echo ok
51## stdout: ok
52## status: 0
53
54#### errexit with &&
55set -o errexit
56echo ok && echo hi | grep nonexistent
57## stdout: ok
58## status: 1
59
60#### errexit test && -- from gen-module-init
61set -o errexit
62test "$mod" = readline && echo "#endif"
63echo status=$?
64## stdout: status=1
65
66#### errexit test && and fail
67set -o errexit
68test -n X && false
69echo status=$?
70## stdout-json: ""
71## status: 1
72
73#### More && ||
74
75$SH -c 'set -e; false || { echo group; false; }; echo bad'
76echo status=$?
77echo
78
79$SH -c 'set -e; false || ( echo subshell; exit 42 ); echo bad'
80echo status=$?
81echo
82
83# noforklast optimization
84$SH -c 'set -e; false || /bin/false; echo bad'
85echo status=$?
86
87## STDOUT:
88group
89status=1
90
91subshell
92status=42
93
94status=1
95## END
96
97#### errexit and loop
98set -o errexit
99for x in 1 2 3; do
100 test $x = 2 && echo "hi $x"
101done
102## stdout: hi 2
103## status: 1
104
105#### errexit and brace group { }
106set -o errexit
107{ test no = yes && echo hi; }
108echo status=$?
109## stdout: status=1
110
111#### errexit and time { }
112set -o errexit
113time false
114echo status=$?
115## status: 1
116
117#### errexit with !
118set -o errexit
119echo one
120! true
121echo two
122! false
123echo three
124## STDOUT:
125one
126two
127three
128## END
129
130#### errexit with ! and ;
131# AST has extra Sentence nodes; there was a REGRESSION here.
132set -o errexit; echo one; ! true; echo two; ! false; echo three
133## STDOUT:
134one
135two
136three
137## END
138
139#### errexit with while/until
140set -o errexit
141while false; do
142 echo ok
143done
144until false; do
145 echo ok # do this once then exit loop
146 break
147done
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?
155set -o errexit
156i=0
157(( i++ ))
158echo 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
165set -o errexit
166( echo one; false; echo two; )
167echo three
168## status: 1
169## STDOUT:
170one
171## END
172
173#### set -o errexit while it's being ignored (moot with strict_errexit)
174set -o errexit
175# osh aborts early here
176if { echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; }; then
177 echo 5;
178fi
179echo 6
180false # this is the one that makes shells fail
181echo 7
182## status: 1
183## STDOUT:
1841
1852
1863
1874
1885
1896
190## END
191
192#### set +o errexit while it's being ignored (moot with strict_errexit)
193set -o errexit
194if { echo 1; false; echo 2; set +o errexit; echo 3; false; echo 4; }; then
195 echo 5;
196fi
197echo 6
198false # does NOT fail, because we restored it.
199echo 7
200## STDOUT:
2011
2022
2033
2044
2055
2066
2077
208## END
209
210#### set +o errexit with 2 levels of ignored
211set -o errexit
212if { echo 1; ! set +o errexit; echo 2; }; then
213 echo 3
214fi
215echo 6
216false
217echo 7
218
219## STDOUT:
2201
2212
2223
2236
2247
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; )
229echo 5
230false
231echo 6
232## STDOUT:
2331
2342
2353
2365
2376
238## END
239
240#### set errexit while it's ignored in a subshell (moot with strict_errexit)
241set -o errexit
242if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
243 echo 5;
244fi
245echo 6 # This is executed because the subshell just returns false
246false
247echo 7
248## status: 1
249## STDOUT:
2501
2512
2523
2534
2545
2556
256## END
257
258#### shopt -s strict:all || true while errexit is on
259set -o errexit
260shopt -s strict:all || true
261echo one
262false # fail
263echo two
264## status: 1
265## STDOUT:
266one
267## END
268
269#### errexit double guard
270# OSH bug fix. ErrExit needs a counter, not a boolean.
271set -o errexit
272if { ! false; false; true; } then
273 echo true
274fi
275false
276echo done
277## status: 1
278## STDOUT:
279true
280## END
281
282#### background processes respect errexit
283set -o errexit
284{ echo one; false; echo two; exit 42; } &
285wait $!
286## status: 1
287## STDOUT:
288one
289## END
290
291#### pipeline process respects errexit
292set -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
300done
301echo four
302## status: 1
303## STDOUT:
304one
305[three]
306## END
307
308#### simple command / assign - redir failure DOES respect errexit
309
310$SH -c '
311set -o errexit
312true > /
313echo builtin status=$?
314'
315echo status=$?
316
317$SH -c '
318set -o errexit
319/bin/true > /
320echo extern status=$?
321'
322echo status=$?
323
324$SH -c '
325set -o errexit
326assign=foo > /
327echo assign status=$?
328'
329echo status=$?
330
331## STDOUT:
332status=1
333status=1
334status=1
335## END
336## OK dash STDOUT:
337status=2
338status=2
339status=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 '
347shopt -s expand_aliases
348
349set -o errexit
350alias zz="{ echo 1; echo 2; }"
351zz > /
352echo alias status=$?
353'
354echo status=$?
355
356## STDOUT:
357status=1
358## END
359
360## BUG dash STDOUT:
361alias status=2
362status=0
363## END
364
365## BUG ash STDOUT:
366alias status=1
367status=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
374case $SH in dash) exit ;; esac
375
376$SH -c '
377set -o errexit
378[[ x = x ]] > /
379echo dbracket status=$?
380'
381echo status=$?
382
383$SH -c '
384set -o errexit
385(( 42 )) > /
386echo dparen status=$?
387'
388echo status=$?
389
390## STDOUT:
391status=1
392status=1
393## END
394
395## OK ash STDOUT:
396status=1
397status=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
411set -o errexit
412
413{ cat ; } < not_exist.txt
414
415echo status=$?
416echo 'should not get here'
417
418## status: 1
419## STDOUT:
420## END
421
422## BUG dash status: 0
423## BUG dash STDOUT:
424status=2
425should not get here
426## END
427
428## BUG ash status: 0
429## BUG ash STDOUT:
430status=1
431should 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
442set -o errexit
443
444while read line; do
445 echo $line
446done < not_exist.txt
447
448echo status=$?
449echo 'should not get here'
450
451## status: 1
452## STDOUT:
453## END
454
455## BUG dash status: 0
456## BUG dash STDOUT:
457status=2
458should not get here
459## END
460
461## BUG ash status: 0
462## BUG ash STDOUT:
463status=1
464should not get here
465## END
466
467
468#### set -e enabled in function (regression)
469foo() {
470 set -e
471 false
472 echo "should be executed"
473}
474#foo && true
475#foo || true
476
477if foo; then
478 true
479fi
480
481echo "should be executed"
482## STDOUT:
483should be executed
484should be executed
485## END
486
487#### set -e in function #2
488foo() {
489 set -e
490 false
491 echo "should be executed"
492}
493! foo
494
495echo "should be executed"
496## BUG bash stdout-json: ""
497## BUG bash status: 1
498## STDOUT:
499should be executed
500should be executed
501## END
502
503
504#### Command sub exit code is lost
505echo ft $(false) $(true)
506echo status=$?
507
508set -o errexit
509shopt -s inherit_errexit || true
510
511# This changes it
512#shopt -s command_sub_errexit || true
513
514echo f $(date %x)
515echo status=$?
516
517# compare with
518# x=$(date %x) # FAILS
519# local x=$(date %x) # does NOT fail
520
521echo ft $(false) $(true)
522echo status=$?
523
524## STDOUT:
525ft
526status=0
527f
528status=0
529ft
530status=0
531## END
532