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