OILS / spec / var-op-bash.test.sh View on Github | oils.pub

554 lines, 309 significant
1## compare_shells: bash
2## oils_failures_allowed: 7
3
4#### Lower Case with , and ,,
5x='ABC DEF'
6echo ${x,}
7echo ${x,,}
8echo empty=${empty,}
9echo empty=${empty,,}
10## STDOUT:
11aBC DEF
12abc def
13empty=
14empty=
15## END
16
17#### Upper Case with ^ and ^^
18x='abc def'
19echo ${x^}
20echo ${x^^}
21echo empty=${empty^}
22echo empty=${empty^^}
23## STDOUT:
24Abc def
25ABC DEF
26empty=
27empty=
28## END
29
30#### Case folding - Unicode characters
31
32# https://www.utf8-chartable.de/unicode-utf8-table.pl
33
34x=$'\u00C0\u00C8' # upper grave
35y=$'\u00E1\u00E9' # lower acute
36
37echo u ${x^}
38echo U ${x^^}
39
40echo l ${x,}
41echo L ${x,,}
42
43echo u ${y^}
44echo U ${y^^}
45
46echo l ${y,}
47echo L ${y,,}
48
49## STDOUT:
50u ÀÈ
51U ÀÈ
52l àÈ
53L àè
54u Áé
55U ÁÉ
56l áé
57L áé
58## END
59
60#### Case folding - multi code point
61
62echo shell
63small=$'\u00DF'
64echo u ${small^}
65echo U ${small^^}
66
67echo l ${small,}
68echo L ${small,,}
69echo
70
71echo python2
72python2 -c '
73small = u"\u00DF"
74print(small.upper().encode("utf-8"))
75print(small.lower().encode("utf-8"))
76'
77echo
78
79# Not in the container images, but python 3 DOES support it!
80# This is moved to demo/survey-case-fold.sh
81
82if false; then
83echo python3
84python3 -c '
85import sys
86small = u"\u00DF"
87sys.stdout.buffer.write(small.upper().encode("utf-8") + b"\n")
88sys.stdout.buffer.write(small.lower().encode("utf-8") + b"\n")
89'
90fi
91
92if 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 '
101fi
102
103## STDOUT:
104## END
105## BUG bash STDOUT:
106shell
107u ß
108U ß
109l ß
110L ß
111
112python2
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
126x='i'
127
128echo u ${x^}
129echo U ${x^^}
130
131echo l ${x,}
132echo L ${x,,}
133
134## OK bash/osh STDOUT:
135u I
136U I
137l i
138L i
139## END
140
141#### Lower Case with constant string (VERY WEIRD)
142x='AAA ABC DEF'
143echo ${x,A}
144echo ${x,,A} # replaces every A only?
145## STDOUT:
146aAA ABC DEF
147aaa aBC DEF
148## END
149
150#### Lower Case glob
151
152# Hm with C.UTF-8, this does no case folding?
153export LC_ALL=en_US.UTF-8
154
155x='ABC DEF'
156echo ${x,[d-f]}
157echo ${x,,[d-f]} # bash 4.4 fixed in bash 5.2.21
158## STDOUT:
159ABC DEF
160ABC 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
167x='abc DEF'
168
169echo "${x@u}"
170
171echo "${x@U}"
172
173echo "${x@L}"
174
175## STDOUT:
176Abc DEF
177ABC DEF
178abc def
179## END
180
181
182#### ${x@Q}
183x="FOO'BAR spam\"eggs"
184eval "new=${x@Q}"
185test "$x" = "$new" && echo OK
186## STDOUT:
187OK
188## END
189
190#### ${array@Q} and ${array[@]@Q}
191array=(x 'y\nz')
192echo ${array[@]@Q}
193echo ${array@Q}
194echo ${array@Q}
195## STDOUT:
196'x' 'y\nz'
197'x'
198'x'
199## END
200## OK osh STDOUT:
201x $'y\\nz'
202x
203x
204## END
205
206#### ${!prefix@} ${!prefix*} yields sorted array of var names
207ZOO=zoo
208ZIP=zip
209ZOOM='one two'
210Z='three four'
211
212z=lower
213
214argv.py ${!Z*}
215argv.py ${!Z@}
216argv.py "${!Z*}"
217argv.py "${!Z@}"
218for i in 1 2; do argv.py ${!Z*} ; done
219for i in 1 2; do argv.py ${!Z@} ; done
220for i in 1 2; do argv.py "${!Z*}"; done
221for 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)
238hello1=1 hello2=2 hello3=3
239echo ${!hello@}
240hello=()
241echo ${!hello@}
242## STDOUT:
243hello1 hello2 hello3
244hello hello1 hello2 hello3
245## END
246
247#### ${var@a} for attributes
248array=(one two)
249echo ${array@a}
250declare -r array=(one two)
251echo ${array@a}
252declare -rx PYTHONPATH=hi
253echo ${PYTHONPATH@a}
254
255# bash and osh differ here
256#declare -rxn x=z
257#echo ${x@a}
258## STDOUT:
259a
260ar
261rx
262## END
263
264#### ${var@a} error conditions
265echo [${?@a}]
266## STDOUT:
267[]
268## END
269
270#### undef and @P @Q @a
271$SH -c 'echo ${undef@P}'
272echo status=$?
273$SH -c 'echo ${undef@Q}'
274echo status=$?
275$SH -c 'echo ${undef@a}'
276echo status=$?
277## STDOUT:
278
279status=0
280
281status=0
282
283status=0
284## END
285
286
287#### argv array and @P @Q @a
288$SH -c 'echo ${@@P}' dummy a b c
289echo status=$?
290$SH -c 'echo ${@@Q}' dummy a 'b\nc'
291echo status=$?
292$SH -c 'echo ${@@a}' dummy a b c
293echo status=$?
294## STDOUT:
295a b c
296status=0
297'a' 'b\nc'
298status=0
299
300status=0
301## END
302## OK osh STDOUT:
303a b c
304status=0
305a $'b\\nc'
306status=0
307a a a
308status=0
309## END
310
311#### assoc array and @P @Q @a
312
313# note: "y z" causes a bug!
314$SH -c 'declare -A A=(["x"]="y"); echo ${A@P} - ${A[@]@P}'
315echo status=$?
316
317# note: "y z" causes a bug!
318$SH -c 'declare -A A=(["x"]="y"); echo ${A@Q} - ${A[@]@Q}'
319echo status=$?
320
321$SH -c 'declare -A A=(["x"]=y); echo ${A@a} - ${A[@]@a}'
322echo status=$?
323## STDOUT:
324- y
325status=0
326- 'y'
327status=0
328A - A
329status=0
330## END
331## OK osh STDOUT:
332- y
333status=0
334- y
335status=0
336A - A
337status=0
338## END
339
340#### ${!var[@]@X}
341# note: "y z" causes a bug!
342$SH -c 'declare -A A=(["x"]="y"); echo ${!A[@]@P}'
343if test $? -ne 0; then echo fail; fi
344
345# note: "y z" causes a bug!
346$SH -c 'declare -A A=(["x y"]="y"); echo ${!A[@]@Q}'
347if test $? -ne 0; then echo fail; fi
348
349$SH -c 'declare -A A=(["x"]=y); echo ${!A[@]@a}'
350if test $? -ne 0; then echo fail; fi
351# STDOUT:
352
353
354
355# END
356## OK osh STDOUT:
357fail
358'x y'
359a
360## END
361
362#### ${#var@X} is a parse error
363# note: "y z" causes a bug!
364$SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@P}'
365if test $? -ne 0; then echo fail; fi
366
367# note: "y z" causes a bug!
368$SH -c 'declare -A A=(["x"]="y"); echo ${#A[@]@Q}'
369if test $? -ne 0; then echo fail; fi
370
371$SH -c 'declare -A A=(["x"]=y); echo ${#A[@]@a}'
372if test $? -ne 0; then echo fail; fi
373## STDOUT:
374fail
375fail
376fail
377## END
378
379#### ${!A@a} and ${!A[@]@a}
380declare -A A=(["x"]=y)
381echo x=${!A[@]@a}
382echo invalid=${!A@a}
383
384# OSH prints 'a' for indexed array because the AssocArray with ! turns into
385# it. Disallowing it would be the other reasonable behavior.
386
387## status: 1
388## STDOUT:
389x=
390## END
391
392# Bash succeeds with ${!A@a}, which references the variable named as $A (i.e.,
393# ''). This must be a Bash bug since the behavior is inconsistent with the
394# fact that ${!undef@a} and ${!empty@a} fail.
395
396## BUG bash status: 0
397## BUG bash STDOUT:
398x=
399invalid=
400## END
401
402#### undef vs. empty string in var ops
403
404empty=''
405x=x
406
407echo ${x@Q} ${empty@Q} ${undef@Q} ${x@Q}
408
409echo ${x@K} ${empty@K} ${undef@K} ${x@K}
410
411echo ${x@k} ${empty@k} ${undef@k} ${x@k}
412
413echo ${x@A} ${empty@A} ${undef@A} ${x@A}
414
415declare -r x
416echo ${x@a} ${empty@a} ${undef@a} ${x@a}
417
418# x x
419#echo ${x@E} ${empty@E} ${undef@E} ${x@E}
420# x x
421#echo ${x@P} ${empty@P} ${undef@P} ${x@P}
422
423## STDOUT:
424'x' '' 'x'
425'x' '' 'x'
426'x' '' 'x'
427x='x' empty='' x='x'
428r r
429## END
430
431#### -o nounset with var ops
432
433set -u
434(echo ${undef@Q}); echo "stat: $?"
435(echo ${undef@P}); echo "stat: $?"
436(echo ${undef@a}); echo "stat: $?"
437
438## STDOUT:
439stat: 1
440stat: 1
441stat: 1
442## END
443
444
445#### ${a[0]@a} and ${a@a}
446
447a=(1 2 3)
448echo "attr = '${a[0]@a}'"
449echo "attr = '${a@a}'"
450
451## STDOUT:
452attr = 'a'
453attr = 'a'
454## END
455
456
457#### ${!r@a} with r='a[0]' (attribute for indirect expansion of an array element)
458
459a=(1 2 3)
460r='a'
461echo ${!r@a}
462r='a[0]'
463echo ${!r@a}
464
465declare -A d=([0]=foo [1]=bar)
466r='d'
467echo ${!r@a}
468r='d[0]'
469echo ${!r@a}
470
471## STDOUT:
472a
473a
474A
475A
476## END
477
478
479#### Array expansion with nullary var ops
480
481declare -a a=({1..9})
482declare -A A=(['a']=hello ['b']=world ['c']=osh ['d']=ysh)
483
484echo "@Q"
485argv.py "${a[@]@Q}"
486argv.py "${a[*]@Q}"
487argv.py "${A[@]@Q}"
488argv.py "${A[*]@Q}"
489argv.py "${u[@]@Q}"
490argv.py "${u[*]@Q}"
491
492echo "@P"
493argv.py "${a[@]@P}"
494argv.py "${a[*]@P}"
495argv.py "${A[@]@P}"
496argv.py "${A[*]@P}"
497argv.py "${u[@]@P}"
498argv.py "${u[*]@P}"
499
500echo "@a"
501argv.py "${a[@]@a}"
502argv.py "${a[*]@a}"
503argv.py "${A[@]@a}"
504argv.py "${A[*]@a}"
505argv.py "${u[@]@a}"
506argv.py "${u[*]@a}"
507
508## STDOUT:
509@Q
510['1', '2', '3', '4', '5', '6', '7', '8', '9']
511['1 2 3 4 5 6 7 8 9']
512['hello', 'world', 'osh', 'ysh']
513['hello world osh ysh']
514[]
515['']
516@P
517['1', '2', '3', '4', '5', '6', '7', '8', '9']
518['1 2 3 4 5 6 7 8 9']
519['hello', 'world', 'osh', 'ysh']
520['hello world osh ysh']
521[]
522['']
523@a
524['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
525['a a a a a a a a a']
526['A', 'A', 'A', 'A']
527['A A A A']
528[]
529['']
530## END
531
532## OK bash STDOUT:
533@Q
534["'1'", "'2'", "'3'", "'4'", "'5'", "'6'", "'7'", "'8'", "'9'"]
535["'1' '2' '3' '4' '5' '6' '7' '8' '9'"]
536["'ysh'", "'osh'", "'world'", "'hello'"]
537["'ysh' 'osh' 'world' 'hello'"]
538[]
539['']
540@P
541['1', '2', '3', '4', '5', '6', '7', '8', '9']
542['1 2 3 4 5 6 7 8 9']
543['ysh', 'osh', 'world', 'hello']
544['ysh osh world hello']
545[]
546['']
547@a
548['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
549['a a a a a a a a a']
550['A', 'A', 'A', 'A']
551['A A A A']
552[]
553['']
554## END