1 ## compare_shells: dash bash-4.4 mksh zsh
2
3 #### implicit for loop
4 # This is like "for i in $@".
5 fun() {
6 for i; do
7 echo $i
8 done
9 echo "finished=$i"
10 }
11 fun 1 2 3
12 ## STDOUT:
13 1
14 2
15 3
16 finished=3
17 ## END
18
19 #### empty for loop (has "in")
20 set -- 1 2 3
21 for i in ; do
22 echo $i
23 done
24 ## STDOUT:
25 ## END
26
27 #### for loop with invalid identifier
28 # should be compile time error, but runtime error is OK too
29 for - in a b c; do
30 echo hi
31 done
32 ## stdout-json: ""
33 ## status: 2
34 ## OK bash/mksh status: 1
35 ## BUG zsh stdout: hi
36 ## BUG zsh status: 1
37
38 #### the word 'in' can be the loop variable
39
40 for in in a b c; do
41 echo $in
42 done
43 echo finished=$in
44 ## STDOUT:
45 a
46 b
47 c
48 finished=c
49 ## END
50
51 #### Tilde expansion within for loop
52 HOME=/home/bob
53 for name in ~/src ~/git; do
54 echo $name
55 done
56 ## STDOUT:
57 /home/bob/src
58 /home/bob/git
59 ## END
60
61 #### Brace Expansion within Array
62 for i in -{a,b} {c,d}-; do
63 echo $i
64 done
65 ## STDOUT:
66 -a
67 -b
68 c-
69 d-
70 ## END
71 ## N-I dash STDOUT:
72 -{a,b}
73 {c,d}-
74 ## END
75
76 #### using loop var outside loop
77 fun() {
78 for i in a b c; do
79 echo $i
80 done
81 echo $i
82 }
83 fun
84 ## status: 0
85 ## STDOUT:
86 a
87 b
88 c
89 c
90 ## END
91
92 #### continue
93 for i in a b c; do
94 echo $i
95 if test $i = b; then
96 continue
97 fi
98 echo $i
99 done
100 ## status: 0
101 ## STDOUT:
102 a
103 a
104 b
105 c
106 c
107 ## END
108
109 #### break
110 for i in a b c; do
111 echo $i
112 if test $i = b; then
113 break
114 fi
115 done
116 ## status: 0
117 ## STDOUT:
118 a
119 b
120 ## END
121
122 #### dynamic control flow (KNOWN INCOMPATIBILITY)
123 # hm would it be saner to make FATAL builtins called break/continue/etc.?
124 # On the other hand, this spits out errors loudly.
125 b=break
126 for i in 1 2 3; do
127 echo $i
128 $b
129 done
130 ## STDOUT:
131 1
132 ## END
133 ## OK osh STDOUT:
134 1
135 2
136 3
137 ## END
138 ## OK osh status: 127
139
140 #### while in while condition
141 # This is a consequence of the grammar
142 while while true; do echo cond; break; done
143 do
144 echo body
145 break
146 done
147 ## STDOUT:
148 cond
149 body
150 ## END
151
152 #### while in pipe
153 x=$(find spec/ | wc -l)
154 y=$(find spec/ | while read path; do
155 echo $path
156 done | wc -l
157 )
158 test $x -eq $y
159 echo status=$?
160 ## stdout: status=0
161
162 #### while in pipe with subshell
163 i=0
164 seq 3 | ( while read foo; do
165 i=$((i+1))
166 #echo $i
167 done
168 echo $i )
169 ## stdout: 3
170
171 #### until loop
172 # This is just the opposite of while? while ! cond?
173 until false; do
174 echo hi
175 break
176 done
177 ## stdout: hi
178
179 #### continue at top level
180 if true; then
181 echo one
182 continue
183 echo two
184 fi
185 ## status: 0
186 ## STDOUT:
187 one
188 two
189 ## END
190 # zsh behaves like strict_control_flow!
191 ## OK zsh status: 1
192 ## OK zsh STDOUT:
193 one
194 ## END
195
196 #### continue in subshell
197 for i in $(seq 2); do
198 echo "> $i"
199 ( if true; then continue; fi; echo "Should not print" )
200 echo subshell status=$?
201 echo ". $i"
202 done
203 ## STDOUT:
204 # osh lets you fail
205 > 1
206 subshell status=1
207 . 1
208 > 2
209 subshell status=1
210 . 2
211 ## END
212 ## OK dash/bash/zsh STDOUT:
213 > 1
214 subshell status=0
215 . 1
216 > 2
217 subshell status=0
218 . 2
219 ## END
220 ## BUG mksh STDOUT:
221 > 1
222 Should not print
223 subshell status=0
224 . 1
225 > 2
226 Should not print
227 subshell status=0
228 . 2
229 ## END
230
231 #### continue in subshell aborts with errexit
232 # The other shells don't let you recover from this programming error!
233 set -o errexit
234 for i in $(seq 2); do
235 echo "> $i"
236 ( if true; then continue; fi; echo "Should not print" )
237 echo 'should fail after subshell'
238 echo ". $i"
239 done
240 ## STDOUT:
241 > 1
242 ## END
243 ## status: 1
244 ## BUG dash/bash/zsh STDOUT:
245 > 1
246 should fail after subshell
247 . 1
248 > 2
249 should fail after subshell
250 . 2
251 ## END
252 ## BUG dash/bash/zsh status: 0
253 ## BUG mksh STDOUT:
254 > 1
255 Should not print
256 should fail after subshell
257 . 1
258 > 2
259 Should not print
260 should fail after subshell
261 . 2
262 ## END
263 ## BUG mksh status: 0
264
265 #### bad arg to break
266 x=oops
267 while true; do
268 echo hi
269 break $x
270 sleep 0.1
271 done
272 ## stdout: hi
273 ## status: 1
274 ## OK dash status: 2
275 ## OK bash status: 128
276
277 #### too many args to continue
278 # OSH treats this as a parse error
279 for x in a b c; do
280 echo $x
281 # bash breaks rather than continue or fatal error!!!
282 continue 1 2 3
283 done
284 echo --
285 ## stdout-json: ""
286 ## status: 2
287 ## BUG bash STDOUT:
288 a
289 --
290 ## END
291 ## BUG bash status: 0
292 ## BUG dash/mksh/zsh STDOUT:
293 a
294 b
295 c
296 --
297 ## END
298 ## BUG dash/mksh/zsh status: 0
299
300 #### break in condition of loop
301 while break; do
302 echo x
303 done
304 echo done
305 ## STDOUT:
306 done
307 ## END
308
309
310 #### break in condition of nested loop
311 for i in 1 2 3; do
312 echo i=$i
313 while break; do
314 echo x
315 done
316 done
317 echo done
318 ## STDOUT:
319 i=1
320 i=2
321 i=3
322 done
323 ## END
324
325 #### return within eval
326 f() {
327 echo one
328 eval 'return'
329 echo two
330 }
331 f
332 ## STDOUT:
333 one
334 ## END
335
336 #### break/continue within eval
337 # NOTE: This changes things
338 # set -e
339 f() {
340 for i in $(seq 5); do
341 if test $i = 2; then
342 eval continue
343 fi
344 if test $i = 4; then
345 eval break
346 fi
347 echo $i
348 done
349
350 eval 'return'
351 echo 'done'
352 }
353 f
354 ## STDOUT:
355 1
356 3
357 ## END
358 ## BUG mksh STDOUT:
359 1
360 2
361 3
362 4
363 5
364 ## END
365
366 #### break/continue within source
367 # NOTE: This changes things
368 # set -e
369
370 cd $REPO_ROOT
371 f() {
372 for i in $(seq 5); do
373 if test $i = 2; then
374 . spec/testdata/continue.sh
375 fi
376 if test $i = 4; then
377 . spec/testdata/break.sh
378 fi
379 echo $i
380 done
381
382 # Return is different!
383 . spec/testdata/return.sh
384 echo done
385 }
386 f
387 ## STDOUT:
388 1
389 3
390 done
391 ## END
392 ## BUG zsh/mksh STDOUT:
393 1
394 2
395 3
396 4
397 5
398 done
399 ## END
400
401 #### top-level break/continue/return (without strict_control_flow)
402 $SH -c 'break; echo break=$?'
403 $SH -c 'continue; echo continue=$?'
404 $SH -c 'return; echo return=$?'
405 ## STDOUT:
406 break=0
407 continue=0
408 ## END
409 ## BUG zsh stdout-json: ""
410 ## BUG bash STDOUT:
411 break=0
412 continue=0
413 return=1
414 ## END
415
416
417 #### multi-level break with argument
418
419 # reported in issue #1459
420
421 counterA=100
422 counterB=100
423
424 while test "$counterA" -gt 0
425 do
426 counterA=$((counterA - 1))
427 while test "$counterB" -gt 0
428 do
429 counterB=$((counterB - 1))
430 if test "$counterB" = 50
431 then
432 break 2
433 fi
434 done
435 done
436
437 echo "$counterA"
438 echo "$counterB"
439
440 ## STDOUT:
441 99
442 50
443 ## END
444
445
446 #### multi-level continue
447
448 for i in 1 2; do
449 for j in a b c; do
450 if test $j = b; then
451 continue
452 fi
453 echo $i $j
454 done
455 done
456
457 echo ---
458
459 for i in 1 2; do
460 for j in a b c; do
461 if test $j = b; then
462 continue 2 # MULTI-LEVEL
463 fi
464 echo $i $j
465 done
466 done
467
468
469 ## STDOUT:
470 1 a
471 1 c
472 2 a
473 2 c
474 ---
475 1 a
476 2 a
477 ## END
478
479