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