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

508 lines, 236 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#### errexit and loop
74set -o errexit
75for x in 1 2 3; do
76 test $x = 2 && echo "hi $x"
77done
78## stdout: hi 2
79## status: 1
80
81#### errexit and brace group { }
82set -o errexit
83{ test no = yes && echo hi; }
84echo status=$?
85## stdout: status=1
86
87#### errexit and time { }
88set -o errexit
89time false
90echo status=$?
91## status: 1
92
93#### errexit with !
94set -o errexit
95echo one
96! true
97echo two
98! false
99echo three
100## STDOUT:
101one
102two
103three
104## END
105
106#### errexit with ! and ;
107# AST has extra Sentence nodes; there was a REGRESSION here.
108set -o errexit; echo one; ! true; echo two; ! false; echo three
109## STDOUT:
110one
111two
112three
113## END
114
115#### errexit with while/until
116set -o errexit
117while false; do
118 echo ok
119done
120until false; do
121 echo ok # do this once then exit loop
122 break
123done
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?
131set -o errexit
132i=0
133(( i++ ))
134echo 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
141set -o errexit
142( echo one; false; echo two; )
143echo three
144## status: 1
145## STDOUT:
146one
147## END
148
149#### set -o errexit while it's being ignored (moot with strict_errexit)
150set -o errexit
151# osh aborts early here
152if { echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4; }; then
153 echo 5;
154fi
155echo 6
156false # this is the one that makes shells fail
157echo 7
158## status: 1
159## STDOUT:
1601
1612
1623
1634
1645
1656
166## END
167
168#### set +o errexit while it's being ignored (moot with strict_errexit)
169set -o errexit
170if { echo 1; false; echo 2; set +o errexit; echo 3; false; echo 4; }; then
171 echo 5;
172fi
173echo 6
174false # does NOT fail, because we restored it.
175echo 7
176## STDOUT:
1771
1782
1793
1804
1815
1826
1837
184## END
185
186#### set +o errexit with 2 levels of ignored
187set -o errexit
188if { echo 1; ! set +o errexit; echo 2; }; then
189 echo 3
190fi
191echo 6
192false
193echo 7
194
195## STDOUT:
1961
1972
1983
1996
2007
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; )
205echo 5
206false
207echo 6
208## STDOUT:
2091
2102
2113
2125
2136
214## END
215
216#### set errexit while it's ignored in a subshell (moot with strict_errexit)
217set -o errexit
218if ( echo 1; false; echo 2; set -o errexit; echo 3; false; echo 4 ); then
219 echo 5;
220fi
221echo 6 # This is executed because the subshell just returns false
222false
223echo 7
224## status: 1
225## STDOUT:
2261
2272
2283
2294
2305
2316
232## END
233
234#### shopt -s strict:all || true while errexit is on
235set -o errexit
236shopt -s strict:all || true
237echo one
238false # fail
239echo two
240## status: 1
241## STDOUT:
242one
243## END
244
245#### errexit double guard
246# OSH bug fix. ErrExit needs a counter, not a boolean.
247set -o errexit
248if { ! false; false; true; } then
249 echo true
250fi
251false
252echo done
253## status: 1
254## STDOUT:
255true
256## END
257
258#### background processes respect errexit
259set -o errexit
260{ echo one; false; echo two; exit 42; } &
261wait $!
262## status: 1
263## STDOUT:
264one
265## END
266
267#### pipeline process respects errexit
268set -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
276done
277echo four
278## status: 1
279## STDOUT:
280one
281[three]
282## END
283
284#### simple command / assign - redir failure DOES respect errexit
285
286$SH -c '
287set -o errexit
288true > /
289echo builtin status=$?
290'
291echo status=$?
292
293$SH -c '
294set -o errexit
295/bin/true > /
296echo extern status=$?
297'
298echo status=$?
299
300$SH -c '
301set -o errexit
302assign=foo > /
303echo assign status=$?
304'
305echo status=$?
306
307## STDOUT:
308status=1
309status=1
310status=1
311## END
312## OK dash STDOUT:
313status=2
314status=2
315status=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 '
323shopt -s expand_aliases
324
325set -o errexit
326alias zz="{ echo 1; echo 2; }"
327zz > /
328echo alias status=$?
329'
330echo status=$?
331
332## STDOUT:
333status=1
334## END
335
336## BUG dash STDOUT:
337alias status=2
338status=0
339## END
340
341## BUG ash STDOUT:
342alias status=1
343status=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
350case $SH in dash) exit ;; esac
351
352$SH -c '
353set -o errexit
354[[ x = x ]] > /
355echo dbracket status=$?
356'
357echo status=$?
358
359$SH -c '
360set -o errexit
361(( 42 )) > /
362echo dparen status=$?
363'
364echo status=$?
365
366## STDOUT:
367status=1
368status=1
369## END
370
371## OK ash STDOUT:
372status=1
373status=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
387set -o errexit
388
389{ cat ; } < not_exist.txt
390
391echo status=$?
392echo 'should not get here'
393
394## status: 1
395## STDOUT:
396## END
397
398## BUG dash status: 0
399## BUG dash STDOUT:
400status=2
401should not get here
402## END
403
404## BUG ash status: 0
405## BUG ash STDOUT:
406status=1
407should 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
418set -o errexit
419
420while read line; do
421 echo $line
422done < not_exist.txt
423
424echo status=$?
425echo 'should not get here'
426
427## status: 1
428## STDOUT:
429## END
430
431## BUG dash status: 0
432## BUG dash STDOUT:
433status=2
434should not get here
435## END
436
437## BUG ash status: 0
438## BUG ash STDOUT:
439status=1
440should not get here
441## END
442
443
444#### set -e enabled in function (regression)
445foo() {
446 set -e
447 false
448 echo "should be executed"
449}
450#foo && true
451#foo || true
452
453if foo; then
454 true
455fi
456
457echo "should be executed"
458## STDOUT:
459should be executed
460should be executed
461## END
462
463#### set -e in function #2
464foo() {
465 set -e
466 false
467 echo "should be executed"
468}
469! foo
470
471echo "should be executed"
472## BUG bash stdout-json: ""
473## BUG bash status: 1
474## STDOUT:
475should be executed
476should be executed
477## END
478
479
480#### Command sub exit code is lost
481echo ft $(false) $(true)
482echo status=$?
483
484set -o errexit
485shopt -s inherit_errexit || true
486
487# This changes it
488#shopt -s command_sub_errexit || true
489
490echo f $(date %x)
491echo status=$?
492
493# compare with
494# x=$(date %x) # FAILS
495# local x=$(date %x) # does NOT fail
496
497echo ft $(false) $(true)
498echo status=$?
499
500## STDOUT:
501ft
502status=0
503f
504status=0
505ft
506status=0
507## END
508