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-json: "/home/foo\n/home/bar\n"
153
154 ### Tilde expansion with brace expansion
155 # The brace expansion happens FIRST. After that, the second token has tilde
156 # FIRST, so it gets expanded. The first token has an unexpanded tilde, because
157 # it's not in the leading position.
158 # NOTE: mksh gives different behavior! So it probably doesn't matter that
159 # much...
160 HOME=/home/bob
161 echo {foo~,~}/bar
162 # stdout: foo~/bar /home/bob/bar
163 # OK mksh stdout: foo~/bar ~/bar
164
165 ### Two kinds of tilde expansion
166 # ~/foo and ~bar
167 HOME=/home/bob
168 echo ~{/src,root}
169 # stdout: /home/bob/src /root
170 # OK mksh stdout: ~/src ~root
171
172 ### Tilde expansion come before var expansion
173 HOME=/home/bob
174 foo=~
175 echo $foo
176 foo='~'
177 echo $foo
178 # In the second instance, we expand into a literal ~, and since var expansion
179 # comes after tilde expansion, it is NOT tried again.
180 # stdout-json: "/home/bob\n~\n"
181
182 ### Number range expansion
183 echo -{1..8..3}-
184 # stdout: -1- -4- -7-
185 # N-I mksh stdout: -{1..8..3}-
186
187 ### Ascending number range expansion with negative step
188 echo -{1..8..-3}-
189 # stdout: -1- -4- -7-
190 # OK zsh stdout: -7- -4- -1-
191 # N-I mksh stdout: -{1..8..-3}-
192
193 ### Descending number range expansion
194 echo -{8..1..3}-
195 # stdout: -8- -5- -2-
196 # N-I mksh stdout: -{8..1..3}-
197
198 ### Descending number range expansion with negative step
199 echo -{8..1..-3}-
200 # stdout: -8- -5- -2-
201 # OK zsh stdout: -2- -5- -8-
202 # N-I mksh stdout: -{8..1..-3}-
203
204 ### Char range expansion
205 echo -{a..e}-
206 # stdout: -a- -b- -c- -d- -e-
207 # N-I mksh stdout: -{a..e}-
208
209 ### Char range expansion with step
210 echo -{a..e..2}- -{a..e..-2}-
211 # stdout: -a- -c- -e- -a- -c- -e-
212 # N-I mksh/zsh stdout: -{a..e..2}- -{a..e..-2}-
213
214 ### Descending char range expansion
215 echo -{e..a..2}- -{e..a..-2}-
216 # stdout: -e- -c- -a- -e- -c- -a-
217 # N-I mksh/zsh stdout: -{e..a..2}- -{e..a..-2}-
218
219 ### Fixed width number range expansion
220 echo -{01..03}-
221 # stdout: -01- -02- -03-
222 # N-I mksh stdout: -{01..03}-
223
224 ### Inconsistent fixed width number range expansion
225 # zsh uses the first one, bash uses the max width?
226 echo -{01..003}-
227 # stdout: -001- -002- -003-
228 # OK zsh stdout: -01- -02- -03-
229 # N-I mksh stdout: -{01..003}-
230
231 ### Inconsistent fixed width number range expansion
232 # zsh uses the first width, bash uses the max width?
233 echo -{01..3}-
234 # stdout: -01- -02- -03-
235 # N-I mksh stdout: -{01..3}-
236
237 ### Side effect in expansion
238 # bash is the only one that does it first. I guess since this is
239 # non-POSIX anyway, follow bash?
240 i=0
241 echo {a,b,c}-$((i++))
242 # stdout: a-0 b-1 c-2
243 # OK mksh/zsh stdout: a-0 b-0 c-0