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