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