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