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