1 ## compare_shells: bash mksh zsh
2 ## oils_failures_allowed: 0
3
4 #### no expansion
5 echo {foo}
6 ## stdout: {foo}
7
8 #### incomplete trailing expansion
9 echo {a,b}_{
10 ## stdout: a_{ b_{
11 ## OK osh stdout: {a,b}_{
12
13 #### partial leading expansion
14 echo }_{a,b}
15 ## stdout: }_a }_b
16 ## OK osh stdout: }_{a,b}
17
18 #### partial leading expansion 2
19 echo {x}_{a,b}
20 ## stdout: {x}_a {x}_b
21
22 #### } in expansion
23 # hm they treat this the SAME. Leftmost { is matched by first }, and then
24 # there is another } as the postfix.
25 echo {a,b}}
26 ## stdout: a} b}
27 ## status: 0
28 ## OK osh stdout: {a,b}}
29 ## OK zsh stdout-json: ""
30 ## OK zsh status: 1
31
32 #### single expansion
33 echo {foo,bar}
34 ## stdout: foo bar
35
36 #### double expansion
37 echo {a,b}_{c,d}
38 ## stdout: a_c a_d b_c b_d
39
40 #### triple expansion
41 echo {0,1}{0,1}{0,1}
42 ## stdout: 000 001 010 011 100 101 110 111
43
44 #### double expansion with single and double quotes
45 echo {'a',b}_{c,"d"}
46 ## stdout: a_c a_d b_c b_d
47
48 #### expansion with mixed quotes
49 echo -{\X"b",'cd'}-
50 ## stdout: -Xb- -cd-
51
52 #### expansion with simple var
53 a=A
54 echo -{$a,b}-
55 ## stdout: -A- -b-
56
57 #### double expansion with simple var -- bash bug
58 # bash is inconsistent with the above
59 a=A
60 echo {$a,b}_{c,d}
61 ## stdout: A_c A_d b_c b_d
62 ## BUG bash stdout: b_c b_d
63
64 #### double expansion with braced variable
65 # This fixes it
66 a=A
67 echo {${a},b}_{c,d}
68 ## stdout: A_c A_d b_c b_d
69
70 #### double expansion with literal and simple var
71 a=A
72 echo {_$a,b}_{c,d}
73 ## stdout: _A_c _A_d b_c b_d
74 ## BUG bash stdout: _ _ b_c b_d
75
76 #### expansion with command sub
77 a=A
78 echo -{$(echo a),b}-
79 ## stdout: -a- -b-
80
81 #### expansion with arith sub
82 a=A
83 echo -{$((1 + 2)),b}-
84 ## stdout: -3- -b-
85
86 #### double expansion with escaped literals
87 a=A
88 echo -{\$,\[,\]}-
89 ## stdout: -$- -[- -]-
90
91 #### { in expansion
92 # bash and mksh treat this differently. bash treats the
93 # first { is a prefix. I think it's harder to read, and \{{a,b} should be
94 # required.
95 echo {{a,b}
96 ## stdout: {{a,b}
97 ## BUG bash/zsh stdout: {a {b
98
99 #### quoted { in expansion
100 echo \{{a,b}
101 ## stdout: {a {b
102
103 #### Empty expansion
104 echo a{X,,Y}b
105 ## stdout: aXb ab aYb
106
107 #### Empty alternative
108 # zsh and mksh don't do word elision, probably because they do brace expansion
109 # AFTER variable substitution.
110 argv.py {X,,Y,}
111 ## stdout: ['X', 'Y']
112 ## OK mksh/zsh stdout: ['X', '', 'Y', '']
113 ## status: 0
114
115 #### Empty alternative with empty string suffix
116 # zsh and mksh don't do word elision, probably because they do brace expansion
117 # AFTER variable substitution.
118 argv.py {X,,Y,}''
119 ## stdout: ['X', '', 'Y', '']
120 ## status: 0
121
122 #### nested brace expansion
123 echo -{A,={a,b}=,B}-
124 ## stdout: -A- -=a=- -=b=- -B-
125
126 #### triple nested brace expansion
127 echo -{A,={a,.{x,y}.,b}=,B}-
128 ## stdout: -A- -=a=- -=.x.=- -=.y.=- -=b=- -B-
129
130 #### nested and double brace expansion
131 echo -{A,={a,b}{c,d}=,B}-
132 ## stdout: -A- -=ac=- -=ad=- -=bc=- -=bd=- -B-
133
134 #### expansion on RHS of assignment
135 # I think bash's behavior is more consistent. No splitting either.
136 v={X,Y}
137 echo $v
138 ## stdout: {X,Y}
139 ## BUG mksh stdout: X Y
140
141 #### no expansion with RHS assignment
142 {v,x}=X
143 ## status: 127
144 ## stdout-json: ""
145 ## OK zsh status: 1
146
147 #### Tilde expansion
148 HOME=/home/foo
149 echo ~
150 HOME=/home/bar
151 echo ~
152 ## STDOUT:
153 /home/foo
154 /home/bar
155 ## END
156
157 #### Tilde expansion with brace expansion
158
159 # The brace expansion happens FIRST. After that, the second token has tilde
160 # FIRST, so it gets expanded. The first token has an unexpanded tilde, because
161 # it's not in the leading position.
162
163 HOME=/home/bob
164
165 # Command
166
167 echo {foo~,~}/bar
168
169 # Loop
170
171 for x in {foo~,~}/bar; do
172 echo -- $x
173 done
174
175 # Array
176
177 a=({foo~,~}/bar)
178
179 for y in "${a[@]}"; do
180 echo "== $y"
181 done
182
183 ## STDOUT:
184 foo~/bar /home/bob/bar
185 -- foo~/bar
186 -- /home/bob/bar
187 == foo~/bar
188 == /home/bob/bar
189 ## END
190
191 ## BUG mksh STDOUT:
192 foo~/bar ~/bar
193 -- foo~/bar
194 -- ~/bar
195 == foo~/bar
196 == ~/bar
197 ## END
198
199 #### Two kinds of tilde expansion
200
201 HOME=/home/bob
202
203 # Command
204 echo ~{/src,root}
205
206 # Loop
207
208 for x in ~{/src,root}; do
209 echo -- $x
210 done
211
212 # Array
213
214 a=(~{/src,root})
215
216 for y in "${a[@]}"; do
217 echo "== $y"
218 done
219
220 ## STDOUT:
221 /home/bob/src /root
222 -- /home/bob/src
223 -- /root
224 == /home/bob/src
225 == /root
226 ## END
227
228 ## BUG mksh STDOUT:
229 ~/src ~root
230 -- ~/src
231 -- ~root
232 == ~/src
233 == ~root
234 ## END
235
236 #### Tilde expansion come before var expansion
237 HOME=/home/bob
238 foo=~
239 echo $foo
240 foo='~'
241 echo $foo
242 # In the second instance, we expand into a literal ~, and since var expansion
243 # comes after tilde expansion, it is NOT tried again.
244 ## STDOUT:
245 /home/bob
246 ~
247 ## END
248
249 #### Number range expansion
250 echo -{1..8..3}-
251 echo -{1..10..3}-
252 ## STDOUT:
253 -1- -4- -7-
254 -1- -4- -7- -10-
255 ## N-I mksh STDOUT:
256 -{1..8..3}-
257 -{1..10..3}-
258 ## END
259
260 #### Ascending number range expansion with negative step is invalid
261 echo -{1..8..-3}-
262 ## stdout-json: ""
263 ## status: 2
264 ## BUG bash stdout: -1- -4- -7-
265 ## BUG zsh stdout: -7- -4- -1-
266 ## BUG bash/zsh status: 0
267 ## N-I mksh stdout: -{1..8..-3}-
268 ## N-I mksh status: 0
269
270 #### regression: -1 step disallowed
271 echo -{1..4..-1}-
272 ## stdout-json: ""
273 ## status: 2
274 ## BUG bash stdout: -1- -2- -3- -4-
275 ## BUG zsh stdout: -4- -3- -2- -1-
276 ## BUG bash/zsh status: 0
277 ## N-I mksh stdout: -{1..4..-1}-
278 ## N-I mksh status: 0
279
280 #### regression: 0 step disallowed
281 echo -{1..4..0}-
282 ## stdout-json: ""
283 ## status: 2
284 ## BUG bash stdout: -1- -2- -3- -4-
285 ## BUG zsh stdout: -1..4..0-
286 ## BUG bash/zsh status: 0
287 ## N-I mksh stdout: -{1..4..0}-
288 ## N-I mksh status: 0
289
290 #### Descending number range expansion with positive step is invalid
291 echo -{8..1..3}-
292 ## stdout-json: ""
293 ## status: 2
294 ## BUG bash/zsh stdout: -8- -5- -2-
295 ## BUG bash/zsh status: 0
296 ## N-I mksh stdout: -{8..1..3}-
297 ## N-I mksh status: 0
298
299 #### Descending number range expansion with negative step
300 echo -{8..1..-3}-
301 ## stdout: -8- -5- -2-
302 # zsh behavior seems clearly wrong!
303 ## BUG zsh stdout: -2- -5- -8-
304 ## N-I mksh stdout: -{8..1..-3}-
305
306 #### Singleton ranges
307 echo {1..1}-
308 echo {-9..-9}-
309 echo {-9..-9..3}-
310 echo {-9..-9..-3}-
311 echo {a..a}-
312 ## STDOUT:
313 1-
314 -9-
315 -9-
316 -9-
317 a-
318 ## END
319 ## N-I mksh STDOUT:
320 {1..1}-
321 {-9..-9}-
322 {-9..-9..3}-
323 {-9..-9..-3}-
324 {a..a}-
325 ## END
326
327 #### Singleton char ranges with steps
328 echo {a..a..2}-
329 echo {a..a..-2}-
330 ## STDOUT:
331 a-
332 a-
333 ## END
334 # zsh is considered buggy because it implements {a..a} but not {a..a..1} !
335 ## BUG zsh STDOUT:
336 {a..a..2}-
337 {a..a..-2}-
338 ## END
339 ## N-I mksh STDOUT:
340 {a..a..2}-
341 {a..a..-2}-
342 ## END
343
344 #### Char range expansion
345 echo -{a..e}-
346 ## stdout: -a- -b- -c- -d- -e-
347 ## N-I mksh stdout: -{a..e}-
348
349 #### Char range expansion with step
350 echo -{a..e..2}-
351 ## stdout: -a- -c- -e-
352 ## N-I mksh/zsh stdout: -{a..e..2}-
353
354 #### Char ranges with steps of the wrong sign
355 echo -{a..e..-2}-
356 echo -{e..a..2}-
357 ## stdout-json: ""
358 ## status: 2
359 ## BUG bash STDOUT:
360 -a- -c- -e-
361 -e- -c- -a-
362 ## END
363 ## BUG bash status: 0
364 ## N-I mksh/zsh STDOUT:
365 -{a..e..-2}-
366 -{e..a..2}-
367 ## END
368 ## N-I mksh/zsh status: 0
369
370 #### Mixed case char expansion is invalid
371 case $SH in *zsh) echo BUG; exit ;; esac
372 echo -{z..A}-
373 echo -{z..A..2}-
374 ## stdout-json: ""
375 ## status: 2
376 ## OK mksh STDOUT:
377 -{z..A}-
378 -{z..A..2}-
379 ## END
380 ## OK mksh status: 0
381 ## BUG zsh stdout: BUG
382 ## BUG zsh status: 0
383 # This is exposed a weird bash bug!!!
384 ## BUG bash stdout-json: ""
385 ## BUG bash status: 1
386
387 #### Descending char range expansion
388 echo -{e..a..-2}-
389 ## stdout: -e- -c- -a-
390 ## N-I mksh/zsh stdout: -{e..a..-2}-
391
392 #### Fixed width number range expansion
393 echo -{01..03}-
394 echo -{09..12}- # doesn't become -012-, fixed width
395 echo -{12..07}-
396 ## STDOUT:
397 -01- -02- -03-
398 -09- -10- -11- -12-
399 -12- -11- -10- -09- -08- -07-
400 ## END
401 ## N-I mksh STDOUT:
402 -{01..03}-
403 -{09..12}-
404 -{12..07}-
405 ## END
406
407 #### Inconsistent fixed width number range expansion
408 # zsh uses the first one, bash uses the max width?
409 echo -{01..003}-
410 ## stdout: -001- -002- -003-
411 ## OK zsh stdout: -01- -02- -03-
412 ## N-I mksh stdout: -{01..003}-
413
414 #### Inconsistent fixed width number range expansion
415 # zsh uses the first width, bash uses the max width?
416 echo -{01..3}-
417 ## stdout: -01- -02- -03-
418 ## N-I mksh stdout: -{01..3}-
419
420 #### Adjacent comma and range works
421 echo -{a,b}{1..3}-
422 ## STDOUT:
423 -a1- -a2- -a3- -b1- -b2- -b3-
424 ## END
425 ## N-I mksh STDOUT:
426 -a{1..3}- -b{1..3}-
427 ## END
428
429 #### Range inside comma works
430 echo -{a,_{1..3}_,b}-
431 ## STDOUT:
432 -a- -_1_- -_2_- -_3_- -b-
433 ## END
434 ## N-I mksh STDOUT:
435 -a- -_{1..3}_- -b-
436 ## END
437
438 #### Mixed comma and range doesn't work
439 echo -{a,b,1..3}-
440 ## STDOUT:
441 -a- -b- -1..3-
442 ## END
443
444 #### comma and invalid range (adjacent and nested)
445 echo -{a,b}{1...3}-
446 echo -{a,{1...3}}-
447 echo {a,b}{}
448 ## STDOUT:
449 -a{1...3}- -b{1...3}-
450 -a- -{1...3}-
451 a{} b{}
452 ## END
453 # osh doesn't expand ANYTHING on invalid syntax. That's OK because of the test
454 # case below.
455 ## OK osh STDOUT:
456 -{a,b}{1...3}-
457 -{a,{1...3}}-
458 {a,b}{}
459 ## END
460
461 #### OSH provides an alternative to invalid syntax
462 echo -{a,b}\{1...3\}-
463 echo -{a,\{1...3\}}-
464 echo {a,b}\{\}
465 ## STDOUT:
466 -a{1...3}- -b{1...3}-
467 -a- -{1...3}-
468 a{} b{}
469 ## END
470
471 #### Side effect in expansion
472 # bash is the only one that does it first. I guess since this is
473 # non-POSIX anyway, follow bash?
474 i=0
475 echo {a,b,c}-$((i++))
476 ## stdout: a-0 b-1 c-2
477 ## OK mksh/zsh stdout: a-0 b-0 c-0
478
479 #### Invalid brace expansions don't expand
480 echo {1.3}
481 echo {1...3}
482 echo {1__3}
483 ## STDOUT:
484 {1.3}
485 {1...3}
486 {1__3}
487 ## END
488
489 #### Invalid brace expansions mixing characters and numbers
490 # zsh does something crazy like : ; < = > that I'm not writing
491 case $SH in *zsh) echo BUG; exit ;; esac
492 echo {1..a}
493 echo {z..3}
494 ## STDOUT:
495 {1..a}
496 {z..3}
497 ## END
498 ## BUG zsh STDOUT:
499 BUG
500 ## END
501