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