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 |
|