1 #!/usr/bin/env bash
2
3 #### no expansion
4 echo {foo}
5 ## stdout: {foo}
6
7 #### incomplete trailing expansion
8 echo {a,b}_{
9 ## stdout: a_{ b_{
10 ## OK osh stdout: {a,b}_{
11
12 #### partial leading expansion
13 echo }_{a,b}
14 ## stdout: }_a }_b
15 ## OK osh stdout: }_{a,b}
16
17 #### partial leading expansion 2
18 echo {x}_{a,b}
19 ## stdout: {x}_a {x}_b
20 ## OK osh stdout: {x}_{a,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 # NOTE: osh matches mksh. Is that OK?
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 # NOTE: mksh gives different behavior! So it probably doesn't matter that
163 # much
164 HOME=/home/bob
165 echo {foo~,~}/bar
166 ## stdout: foo~/bar /home/bob/bar
167 ## OK osh/mksh stdout: foo~/bar ~/bar
168
169 #### Two kinds of tilde expansion
170 # NOTE: osh matches mksh. Is that OK?
171 # ~/foo and ~bar
172 HOME=/home/bob
173 echo ~{/src,root}
174 ## stdout: /home/bob/src /root
175 ## OK osh/mksh stdout: ~/src ~root
176
177 #### Tilde expansion come before var expansion
178 HOME=/home/bob
179 foo=~
180 echo $foo
181 foo='~'
182 echo $foo
183 # In the second instance, we expand into a literal ~, and since var expansion
184 # comes after tilde expansion, it is NOT tried again.
185 ## STDOUT:
186 /home/bob
187 ~
188 ## END
189
190 #### Number range expansion
191 echo -{1..8..3}-
192 echo -{1..10..3}-
193 ## STDOUT:
194 -1- -4- -7-
195 -1- -4- -7- -10-
196 ## N-I mksh STDOUT:
197 -{1..8..3}-
198 -{1..10..3}-
199 ## END
200
201 #### Ascending number range expansion with negative step is invalid
202 echo -{1..8..-3}-
203 ## stdout-json: ""
204 ## status: 2
205 ## BUG bash stdout: -1- -4- -7-
206 ## BUG zsh stdout: -7- -4- -1-
207 ## BUG bash/zsh status: 0
208 ## N-I mksh stdout: -{1..8..-3}-
209 ## N-I mksh status: 0
210
211 #### regression: -1 step disallowed
212 echo -{1..4..-1}-
213 ## stdout-json: ""
214 ## status: 2
215 ## BUG bash stdout: -1- -2- -3- -4-
216 ## BUG zsh stdout: -4- -3- -2- -1-
217 ## BUG bash/zsh status: 0
218 ## N-I mksh stdout: -{1..4..-1}-
219 ## N-I mksh status: 0
220
221 #### regression: 0 step disallowed
222 echo -{1..4..0}-
223 ## stdout-json: ""
224 ## status: 2
225 ## BUG bash stdout: -1- -2- -3- -4-
226 ## BUG zsh stdout: -1..4..0-
227 ## BUG bash/zsh status: 0
228 ## N-I mksh stdout: -{1..4..0}-
229 ## N-I mksh status: 0
230
231 #### Descending number range expansion with positive step is invalid
232 echo -{8..1..3}-
233 ## stdout-json: ""
234 ## status: 2
235 ## BUG bash/zsh stdout: -8- -5- -2-
236 ## BUG bash/zsh status: 0
237 ## N-I mksh stdout: -{8..1..3}-
238 ## N-I mksh status: 0
239
240 #### Descending number range expansion with negative step
241 echo -{8..1..-3}-
242 ## stdout: -8- -5- -2-
243 # zsh behavior seems clearly wrong!
244 ## BUG zsh stdout: -2- -5- -8-
245 ## N-I mksh stdout: -{8..1..-3}-
246
247 #### Singleton ranges
248 echo {1..1}-
249 echo {-9..-9}-
250 echo {-9..-9..3}-
251 echo {-9..-9..-3}-
252 echo {a..a}-
253 ## STDOUT:
254 1-
255 -9-
256 -9-
257 -9-
258 a-
259 ## END
260 ## N-I mksh STDOUT:
261 {1..1}-
262 {-9..-9}-
263 {-9..-9..3}-
264 {-9..-9..-3}-
265 {a..a}-
266 ## END
267
268 #### Singleton char ranges with steps
269 echo {a..a..2}-
270 echo {a..a..-2}-
271 ## STDOUT:
272 a-
273 a-
274 ## END
275 # zsh is considered buggy because it implements {a..a} but not {a..a..1} !
276 ## BUG zsh STDOUT:
277 {a..a..2}-
278 {a..a..-2}-
279 ## END
280 ## N-I mksh STDOUT:
281 {a..a..2}-
282 {a..a..-2}-
283 ## END
284
285 #### Char range expansion
286 echo -{a..e}-
287 ## stdout: -a- -b- -c- -d- -e-
288 ## N-I mksh stdout: -{a..e}-
289
290 #### Char range expansion with step
291 echo -{a..e..2}-
292 ## stdout: -a- -c- -e-
293 ## N-I mksh/zsh stdout: -{a..e..2}-
294
295 #### Char ranges with steps of the wrong sign
296 echo -{a..e..-2}-
297 echo -{e..a..2}-
298 ## stdout-json: ""
299 ## status: 2
300 ## BUG bash STDOUT:
301 -a- -c- -e-
302 -e- -c- -a-
303 ## END
304 ## BUG bash status: 0
305 ## N-I mksh/zsh STDOUT:
306 -{a..e..-2}-
307 -{e..a..2}-
308 ## END
309 ## BUG mksh/zsh status: 0
310
311 #### Mixed case char expansion is invalid
312 case $SH in *zsh) echo BUG; exit ;; esac
313 echo -{z..A}-
314 echo -{z..A..2}-
315 ## stdout-json: ""
316 ## status: 2
317 ## OK mksh STDOUT:
318 -{z..A}-
319 -{z..A..2}-
320 ## END
321 ## OK mksh status: 0
322 ## BUG zsh stdout: BUG
323 ## BUG zsh status: 0
324 # This is exposed a weird bash bug!!!
325 ## BUG bash stdout-json: ""
326 ## BUG bash status: 1
327
328 #### Descending char range expansion
329 echo -{e..a..-2}-
330 ## stdout: -e- -c- -a-
331 ## N-I mksh/zsh stdout: -{e..a..-2}-
332
333 #### Fixed width number range expansion
334 echo -{01..03}-
335 echo -{09..12}- # doesn't become -012-, fixed width
336 echo -{12..07}-
337 ## STDOUT:
338 -01- -02- -03-
339 -09- -10- -11- -12-
340 -12- -11- -10- -09- -08- -07-
341 ## END
342 ## N-I mksh STDOUT:
343 -{01..03}-
344 -{09..12}-
345 -{12..07}-
346 ## END
347
348 #### Inconsistent fixed width number range expansion
349 # zsh uses the first one, bash uses the max width?
350 echo -{01..003}-
351 ## stdout: -001- -002- -003-
352 ## OK zsh stdout: -01- -02- -03-
353 ## N-I mksh stdout: -{01..003}-
354
355 #### Inconsistent fixed width number range expansion
356 # zsh uses the first width, bash uses the max width?
357 echo -{01..3}-
358 ## stdout: -01- -02- -03-
359 ## N-I mksh stdout: -{01..3}-
360
361 #### Adjacent comma and range works
362 echo -{a,b}{1..3}-
363 ## STDOUT:
364 -a1- -a2- -a3- -b1- -b2- -b3-
365 ## END
366 ## N-I mksh STDOUT:
367 -a{1..3}- -b{1..3}-
368 ## END
369
370 #### Range inside comma works
371 echo -{a,_{1..3}_,b}-
372 ## STDOUT:
373 -a- -_1_- -_2_- -_3_- -b-
374 ## END
375 ## N-I mksh STDOUT:
376 -a- -_{1..3}_- -b-
377 ## END
378
379 #### Mixed comma and range doesn't work
380 echo -{a,b,1..3}-
381 ## STDOUT:
382 -a- -b- -1..3-
383 ## END
384
385 #### comma and invalid range (adjacent and nested)
386 echo -{a,b}{1...3}-
387 echo -{a,{1...3}}-
388 echo {a,b}{}
389 ## STDOUT:
390 -a{1...3}- -b{1...3}-
391 -a- -{1...3}-
392 a{} b{}
393 ## END
394 # osh doesn't expand ANYTHING on invalid syntax. That's OK because of the test
395 # case below.
396 ## OK osh STDOUT:
397 -{a,b}{1...3}-
398 -{a,{1...3}}-
399 {a,b}{}
400 ## END
401
402 #### OSH provides an alternative to invalid syntax
403 echo -{a,b}\{1...3\}-
404 echo -{a,\{1...3\}}-
405 echo {a,b}\{\}
406 ## STDOUT:
407 -a{1...3}- -b{1...3}-
408 -a- -{1...3}-
409 a{} b{}
410 ## END
411
412 #### Side effect in expansion
413 # bash is the only one that does it first. I guess since this is
414 # non-POSIX anyway, follow bash?
415 i=0
416 echo {a,b,c}-$((i++))
417 ## stdout: a-0 b-1 c-2
418 ## OK mksh/zsh stdout: a-0 b-0 c-0
419
420 #### Invalid brace expansions don't expand
421 echo {1.3}
422 echo {1...3}
423 echo {1__3}
424 ## STDOUT:
425 {1.3}
426 {1...3}
427 {1__3}
428 ## END
429
430 #### Invalid brace expansions mixing characters and numbers
431 # zsh does something crazy like : ; < = > that I'm not writing
432 case $SH in */zsh) echo BUG; exit ;; esac
433 echo {1..a}
434 echo {z..3}
435 ## STDOUT:
436 {1..a}
437 {z..3}
438 ## END
439 ## BUG zsh STDOUT:
440 BUG
441 ## END
442