1 ## compare_shells: bash
2 ## oils_failures_allowed: 7
3
4 #### Lower Case with , and ,,
5 x='ABC DEF'
6 echo ${x,}
7 echo ${x,,}
8 echo empty=${empty,}
9 echo empty=${empty,,}
10 ## STDOUT:
11 aBC DEF
12 abc def
13 empty=
14 empty=
15 ## END
16
17 #### Upper Case with ^ and ^^
18 x='abc def'
19 echo ${x^}
20 echo ${x^^}
21 echo empty=${empty^}
22 echo empty=${empty^^}
23 ## STDOUT:
24 Abc def
25 ABC DEF
26 empty=
27 empty=
28 ## END
29
30 #### Case folding - Unicode characters
31
32 # https://www.utf8-chartable.de/unicode-utf8-table.pl
33
34 x=$'\u00C0\u00C8' # upper grave
35 y=$'\u00E1\u00E9' # lower acute
36
37 echo u ${x^}
38 echo U ${x^^}
39
40 echo l ${x,}
41 echo L ${x,,}
42
43 echo u ${y^}
44 echo U ${y^^}
45
46 echo l ${y,}
47 echo L ${y,,}
48
49 ## STDOUT:
50 u ÀÈ
51 U ÀÈ
52 l àÈ
53 L àè
54 u Áé
55 U ÁÉ
56 l áé
57 L áé
58 ## END
59
60 #### Case folding - multi code point
61
62 echo shell
63 small=$'\u00DF'
64 echo u ${small^}
65 echo U ${small^^}
66
67 echo l ${small,}
68 echo L ${small,,}
69 echo
70
71 echo python2
72 python2 -c '
73 small = u"\u00DF"
74 print(small.upper().encode("utf-8"))
75 print(small.lower().encode("utf-8"))
76 '
77 echo
78
79 # Not in the container images, but python 3 DOES support it!
80 # This is moved to demo/survey-case-fold.sh
81
82 if false; then
83 echo python3
84 python3 -c '
85 import sys
86 small = u"\u00DF"
87 sys.stdout.buffer.write(small.upper().encode("utf-8") + b"\n")
88 sys.stdout.buffer.write(small.lower().encode("utf-8") + b"\n")
89 '
90 fi
91
92 if false; then
93 # Yes, supported
94 echo node.js
95
96 nodejs -e '
97 var small = "\u00DF"
98 console.log(small.toUpperCase())
99 console.log(small.toLowerCase())
100 '
101 fi
102
103 ## STDOUT:
104 ## END
105 ## BUG bash STDOUT:
106 shell
107 u ß
108 U ß
109 l ß
110 L ß
111
112 python2
113 ß
114 ß
115
116 ## END
117
118 #### Case folding that depends on locale (not enabled, requires Turkish locale)
119
120 # Hm this works in demo/survey-case-fold.sh
121 # Is this a bash 4.4 thing?
122
123 #export LANG='tr_TR.UTF-8'
124 #echo $LANG
125
126 x='i'
127
128 echo u ${x^}
129 echo U ${x^^}
130
131 echo l ${x,}
132 echo L ${x,,}
133
134 ## OK bash/osh STDOUT:
135 u I
136 U I
137 l i
138 L i
139 ## END
140
141 #### Lower Case with constant string (VERY WEIRD)
142 x='AAA ABC DEF'
143 echo ${x,A}
144 echo ${x,,A} # replaces every A only?
145 ## STDOUT:
146 aAA ABC DEF
147 aaa aBC DEF
148 ## END
149
150 #### Lower Case glob
151
152 # Hm with C.UTF-8, this does no case folding?
153 export LC_ALL=en_US.UTF-8
154
155 x='ABC DEF'
156 echo ${x,[d-f]}
157 echo ${x,,[d-f]} # bash 4.4 fixed in bash 5.2.21
158 ## STDOUT:
159 ABC DEF
160 ABC DEF
161 ## END
162
163 #### ${x@u} U L - upper / lower case (bash 5.1 feature)
164
165 # https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
166
167 x='abc DEF'
168
169 echo "${x@u}"
170
171 echo "${x@U}"
172
173 echo "${x@L}"
174
175 ## STDOUT:
176 Abc DEF
177 ABC DEF
178 abc def
179 ## END
180
181
182 #### ${x@Q}
183 x="FOO'BAR spam\"eggs"
184 eval "new=${x@Q}"
185 test "$x" = "$new" && echo OK
186 ## STDOUT:
187 OK
188 ## END
189
190 #### ${array@Q} and ${array[@]@Q}
191 array=(x 'y\nz')
192 echo ${array[@]@Q}
193 echo ${array@Q}
194 echo ${array@Q}
195 ## STDOUT:
196 'x' 'y\nz'
197 'x'
198 'x'
199 ## END
200 ## OK osh STDOUT:
201 x $'y\\nz'
202 x
203 x
204 ## END
205
206 #### ${!prefix@} ${!prefix*} yields sorted array of var names
207 ZOO=zoo
208 ZIP=zip
209 ZOOM='one two'
210 Z='three four'
211
212 z=lower
213
214 argv.py ${!Z*}
215 argv.py ${!Z@}
216 argv.py "${!Z*}"
217 argv.py "${!Z@}"
218 for i in 1 2; do argv.py ${!Z*} ; done
219 for i in 1 2; do argv.py ${!Z@} ; done
220 for i in 1 2; do argv.py "${!Z*}"; done
221 for i in 1 2; do argv.py "${!Z@}"; done
222 ## STDOUT:
223 ['Z', 'ZIP', 'ZOO', 'ZOOM']
224 ['Z', 'ZIP', 'ZOO', 'ZOOM']
225 ['Z ZIP ZOO ZOOM']
226 ['Z', 'ZIP', 'ZOO', 'ZOOM']
227 ['Z', 'ZIP', 'ZOO', 'ZOOM']
228 ['Z', 'ZIP', 'ZOO', 'ZOOM']
229 ['Z', 'ZIP', 'ZOO', 'ZOOM']
230 ['Z', 'ZIP', 'ZOO', 'ZOOM']
231 ['Z ZIP ZOO ZOOM']
232 ['Z ZIP ZOO ZOOM']
233 ['Z', 'ZIP', 'ZOO', 'ZOOM']
234 ['Z', 'ZIP', 'ZOO', 'ZOOM']
235 ## END
236
237 #### ${!prefix@} matches var name (regression)
238 hello1=1 hello2=2 hello3=3
239 echo ${!hello@}
240 hello=()
241 echo ${!hello@}
242 ## STDOUT:
243 hello1 hello2 hello3
244 hello hello1 hello2 hello3
245 ## END
246
247 #### ${var@a} for attributes
248 array=(one two)
249 echo ${array@a}
250 declare -r array=(one two)
251 echo ${array@a}
252 declare -rx PYTHONPATH=hi
253 echo ${PYTHONPATH@a}
254
255 # bash and osh differ here
256 #declare -rxn x=z
257 #echo ${x@a}
258 ## STDOUT:
259 a
260 ar
261 rx
262 ## END
263
264 #### ${var@a} error conditions
265 echo [${?@a}]
266 ## STDOUT:
267 []
268 ## END
269
270 #### undef and @P @Q @a
271 $SH -c 'echo ${undef@P}'
272 echo status=$?
273 $SH -c 'echo ${undef@Q}'
274 echo status=$?
275 $SH -c 'echo ${undef@a}'
276 echo status=$?
277 ## STDOUT:
278
279 status=0
280
281 status=0
282
283 status=0
284 ## END
285
286
287 #### argv array and @P @Q @a
288 $SH -c 'echo ${@@P}' dummy a b c
289 echo status=$?
290 $SH -c 'echo ${@@Q}' dummy a 'b\nc'
291 echo status=$?
292 $SH -c 'echo ${@@a}' dummy a b c
293 echo status=$?
294 ## STDOUT:
295 a b c
296 status=0
297 'a' 'b\nc'
298 status=0
299
300 status=0
301 ## END
302 ## OK osh STDOUT:
303 status=1
304 a $'b\\nc'
305 status=0
306 a
307 status=0
308 ## END
309
310 #### assoc array and @P @Q @a
311
312 # note: "y z" causes a bug!
313 $SH -c 'declare -A A=(["x"]="y"); echo ${A@P} - ${A[@]@P}'
314 echo status=$?
315
316 # note: "y z" causes a bug!
317 $SH -c 'declare -A A=(["x"]="y"); echo ${A@Q} - ${A[@]@Q}'
318 echo status=$?
319
320 $SH -c 'declare -A A=(["x"]=y); echo ${A@a} - ${A[@]@a}'
321 echo status=$?
322 ## STDOUT:
323 - y
324 status=0
325 - 'y'
326 status=0
327 A - A
328 status=0
329 ## END
330 ## OK osh STDOUT:
331 status=1
332 - y
333 status=0
334 A - A
335 status=0
336 ## END
337
338 #### ${!var[@]@X}
339 # note: "y z" causes a bug!
340 $SH -c 'declare -A A=(["x"]="y"); echo ${!A[@]@P}'
341 if test $? -ne 0; then echo fail; fi
342
343 # note: "y z" causes a bug!
344 $SH -c 'declare -A A=(["x y"]="y"); echo ${!A[@]@Q}'
345 if test $? -ne 0; then echo fail; fi
346
347 $SH -c 'declare -A A=(["x"]=y); echo ${!A[@]@a}'
348 if test $? -ne 0; then echo fail; fi
349 # STDOUT:
350
351
352
353 # END
354 ## OK osh STDOUT:
355 fail
356 'x y'
357 a
358 ## END
359
360 #### ${#var@X} is a parse error
361 # note: "y z" causes a bug!
362 $SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@P}'
363 if test $? -ne 0; then echo fail; fi
364
365 # note: "y z" causes a bug!
366 $SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@Q}'
367 if test $? -ne 0; then echo fail; fi
368
369 $SH -c 'declare -A A=(["x"]=y); echo ${#A[@]@a}'
370 if test $? -ne 0; then echo fail; fi
371 ## STDOUT:
372 fail
373 fail
374 fail
375 ## END
376
377 #### ${!A@a} and ${!A[@]@a}
378 declare -A A=(["x"]=y)
379 echo x=${!A[@]@a}
380 echo x=${!A@a}
381
382 # OSH prints 'a' for indexed array because the AssocArray with ! turns into
383 # it. Disallowing it would be the other reasonable behavior.
384
385 ## STDOUT:
386 x=
387 x=
388 ## END
389
390 #### undef vs. empty string in var ops
391
392 empty=''
393 x=x
394
395 echo ${x@Q} ${empty@Q} ${undef@Q} ${x@Q}
396
397 echo ${x@K} ${empty@K} ${undef@K} ${x@K}
398
399 echo ${x@k} ${empty@k} ${undef@k} ${x@k}
400
401 echo ${x@A} ${empty@A} ${undef@A} ${x@A}
402
403 declare -r x
404 echo ${x@a} ${empty@a} ${undef@a} ${x@a}
405
406 # x x
407 #echo ${x@E} ${empty@E} ${undef@E} ${x@E}
408 # x x
409 #echo ${x@P} ${empty@P} ${undef@P} ${x@P}
410
411 ## STDOUT:
412 'x' '' 'x'
413 'x' '' 'x'
414 'x' '' 'x'
415 x='x' empty='' x='x'
416 r r
417 ## END
418
419 #### -o nounset with var ops
420
421 set -u
422 (echo ${undef@Q}); echo "stat: $?"
423 (echo ${undef@P}); echo "stat: $?"
424 (echo ${undef@a}); echo "stat: $?"
425
426 ## STDOUT:
427 stat: 1
428 stat: 1
429 stat: 1
430 ## END