1 #### Lower Case with , and ,,
2 x='ABC DEF'
3 echo ${x,}
4 echo ${x,,}
5 echo empty=${empty,}
6 echo empty=${empty,,}
7 ## STDOUT:
8 aBC DEF
9 abc def
10 empty=
11 empty=
12 ## END
13
14 #### Upper Case with ^ and ^^
15 x='abc def'
16 echo ${x^}
17 echo ${x^^}
18 echo empty=${empty^}
19 echo empty=${empty^^}
20 ## STDOUT:
21 Abc def
22 ABC DEF
23 empty=
24 empty=
25 ## END
26
27 #### Case Folding of Unicode Characters
28
29 # https://www.utf8-chartable.de/unicode-utf8-table.pl
30
31 x=$'\u00C0\u00C8' # upper grave
32 y=$'\u00E1\u00E9' # lower acute
33
34 echo u ${x^}
35 echo U ${x^^}
36
37 echo l ${x,}
38 echo L ${x,,}
39
40 echo u ${y^}
41 echo U ${y^^}
42
43 echo l ${y,}
44 echo L ${y,,}
45
46 ## STDOUT:
47 u ÀÈ
48 U ÀÈ
49 l àÈ
50 L àè
51 u Áé
52 U ÁÉ
53 l áé
54 L áé
55 ## END
56
57 #### Lower Case with constant string (VERY WEIRD)
58 x='AAA ABC DEF'
59 echo ${x,A}
60 echo ${x,,A} # replaces every A only?
61 ## STDOUT:
62 aAA ABC DEF
63 aaa aBC DEF
64 ## END
65
66 #### Lower Case glob
67
68 # Hm with C.UTF-8, this does no case folding?
69 export LC_ALL=en_US.UTF-8
70
71 x='ABC DEF'
72 echo ${x,[d-f]}
73 echo ${x,,[d-f]} # This seems buggy, it doesn't include F?
74 ## STDOUT:
75 ABC DEF
76 ABC deF
77 ## END
78
79 #### ${x@u} U l L upper / lower case (bash 5.1 feature)
80
81 # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
82
83 x='abc def'
84 echo "${x@u}"
85
86 # TODO: we need to upgrade the spec tests to bash 5.1 (or bash 5.2 is coming
87 # out soon)
88
89 ## N-I bash status: 1
90 ## N-I bash STDOUT:
91 ## END
92
93
94 #### ${x@Q}
95 x="FOO'BAR spam\"eggs"
96 eval "new=${x@Q}"
97 test "$x" = "$new" && echo OK
98 ## STDOUT:
99 OK
100 ## END
101
102 #### ${array@Q} and ${array[@]@Q}
103 array=(x 'y\nz')
104 echo ${array[@]@Q}
105 shopt -s compat_array
106 echo ${array@Q}
107 shopt -u compat_array
108 echo ${array@Q}
109 ## STDOUT:
110 'x' 'y\nz'
111 'x'
112 'x'
113 ## END
114 ## OK osh status: 1
115 ## OK osh STDOUT:
116 x $'y\\nz'
117 x
118 ## END
119
120 #### ${!prefix@} ${!prefix*} yields sorted array of var names
121 ZOO=zoo
122 ZIP=zip
123 ZOOM='one two'
124 Z='three four'
125
126 z=lower
127
128 argv.py ${!Z*}
129 argv.py ${!Z@}
130 argv.py "${!Z*}"
131 argv.py "${!Z@}"
132 for i in 1 2; do argv.py ${!Z*} ; done
133 for i in 1 2; do argv.py ${!Z@} ; done
134 for i in 1 2; do argv.py "${!Z*}"; done
135 for i in 1 2; do argv.py "${!Z@}"; done
136 ## STDOUT:
137 ['Z', 'ZIP', 'ZOO', 'ZOOM']
138 ['Z', 'ZIP', 'ZOO', 'ZOOM']
139 ['Z ZIP ZOO ZOOM']
140 ['Z', 'ZIP', 'ZOO', 'ZOOM']
141 ['Z', 'ZIP', 'ZOO', 'ZOOM']
142 ['Z', 'ZIP', 'ZOO', 'ZOOM']
143 ['Z', 'ZIP', 'ZOO', 'ZOOM']
144 ['Z', 'ZIP', 'ZOO', 'ZOOM']
145 ['Z ZIP ZOO ZOOM']
146 ['Z ZIP ZOO ZOOM']
147 ['Z', 'ZIP', 'ZOO', 'ZOOM']
148 ['Z', 'ZIP', 'ZOO', 'ZOOM']
149 ## END
150
151 #### ${!prefix@} matches var name (regression)
152 hello1=1 hello2=2 hello3=3
153 echo ${!hello@}
154 hello=()
155 echo ${!hello@}
156 ## STDOUT:
157 hello1 hello2 hello3
158 hello hello1 hello2 hello3
159 ## END
160
161 #### ${var@a} for attributes
162 array=(one two)
163 echo ${array@a}
164 declare -r array=(one two)
165 echo ${array@a}
166 declare -rx PYTHONPATH=hi
167 echo ${PYTHONPATH@a}
168
169 # bash and osh differ here
170 #declare -rxn x=z
171 #echo ${x@a}
172 ## STDOUT:
173 a
174 ar
175 rx
176 ## END
177
178 #### ${var@a} error conditions
179 echo [${?@a}]
180 ## STDOUT:
181 []
182 ## END
183
184 #### undef and @P @Q @a
185 $SH -c 'echo ${undef@P}'
186 echo status=$?
187 $SH -c 'echo ${undef@Q}'
188 echo status=$?
189 $SH -c 'echo ${undef@a}'
190 echo status=$?
191 ## STDOUT:
192
193 status=0
194
195 status=0
196
197 status=0
198 ## END
199 ## OK osh STDOUT:
200
201 status=0
202 ''
203 status=0
204
205 status=0
206 ## END
207
208
209 #### argv array and @P @Q @a
210 $SH -c 'echo ${@@P}' dummy a b c
211 echo status=$?
212 $SH -c 'echo ${@@Q}' dummy a 'b\nc'
213 echo status=$?
214 $SH -c 'echo ${@@a}' dummy a b c
215 echo status=$?
216 ## STDOUT:
217 a b c
218 status=0
219 'a' 'b\nc'
220 status=0
221
222 status=0
223 ## END
224 ## OK osh STDOUT:
225 status=1
226 a $'b\\nc'
227 status=0
228 a
229 status=0
230 ## END
231
232 #### assoc array and @P @Q @a
233
234 # note: "y z" causes a bug!
235 $SH -c 'declare -A A=(["x"]="y"); echo ${A@P} - ${A[@]@P}'
236 echo status=$?
237
238 # note: "y z" causes a bug!
239 $SH -c 'declare -A A=(["x"]="y"); echo ${A@Q} - ${A[@]@Q}'
240 echo status=$?
241
242 $SH -c 'declare -A A=(["x"]=y); echo ${A@a} - ${A[@]@a}'
243 echo status=$?
244 ## STDOUT:
245 - y
246 status=0
247 - 'y'
248 status=0
249 A - A
250 status=0
251 ## END
252 ## OK osh STDOUT:
253 status=1
254 status=1
255 A - A
256 status=0
257 ## END
258
259 #### ${!var[@]@X}
260 # note: "y z" causes a bug!
261 $SH -c 'declare -A A=(["x"]="y"); echo ${!A[@]@P}'
262 if test $? -ne 0; then echo fail; fi
263
264 # note: "y z" causes a bug!
265 $SH -c 'declare -A A=(["x y"]="y"); echo ${!A[@]@Q}'
266 if test $? -ne 0; then echo fail; fi
267
268 $SH -c 'declare -A A=(["x"]=y); echo ${!A[@]@a}'
269 if test $? -ne 0; then echo fail; fi
270 # STDOUT:
271
272
273
274 # END
275 ## OK osh STDOUT:
276 fail
277 'x y'
278 a
279 ## END
280
281 #### ${#var@X} is a parse error
282 # note: "y z" causes a bug!
283 $SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@P}'
284 if test $? -ne 0; then echo fail; fi
285
286 # note: "y z" causes a bug!
287 $SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@Q}'
288 if test $? -ne 0; then echo fail; fi
289
290 $SH -c 'declare -A A=(["x"]=y); echo ${#A[@]@a}'
291 if test $? -ne 0; then echo fail; fi
292 ## STDOUT:
293 fail
294 fail
295 fail
296 ## END
297
298 #### ${!A@a} and ${!A[@]@a}
299 declare -A A=(["x"]=y)
300 echo x=${!A[@]@a}
301 echo x=${!A@a}
302
303 # OSH prints 'a' for indexed array because the AssocArray with ! turns into
304 # it. Disallowing it would be the other reasonable behavior.
305
306 ## STDOUT:
307 x=
308 x=
309 ## END