1 |
|
2 |
# NOTE: |
3 |
# -declare -A is required. |
4 |
# |
5 |
# Simply doing: |
6 |
# a=([aa]=b [foo]=bar ['a+1']=c) |
7 |
# gets utterly bizarre behavior. |
8 |
# |
9 |
# Associtative Arrays are COMPLETELY bash-specific. mksh doesn't even come |
10 |
# close. So I will probably not implement them, or implement something |
11 |
# slightly different, because the semantics are just wierd. |
12 |
|
13 |
# http://www.gnu.org/software/bash/manual/html_node/Arrays.html |
14 |
# TODO: Need a SETUP section. |
15 |
|
16 |
#### Literal syntax ([x]=y) |
17 |
declare -A a |
18 |
a=([aa]=b [foo]=bar ['a+1']=c) |
19 |
echo ${a["aa"]} |
20 |
echo ${a["foo"]} |
21 |
echo ${a["a+1"]} |
22 |
## STDOUT: |
23 |
b |
24 |
bar |
25 |
c |
26 |
## END |
27 |
|
28 |
#### set associative array to indexed array literal (very surprising bash behavior) |
29 |
declare -A assoc=([k1]=foo [k2]='spam eggs') |
30 |
for v in "${assoc[@]}"; do echo $v; done | sort |
31 |
for v in "${!assoc[@]}"; do echo $v; done | sort |
32 |
|
33 |
# disallow this in OSH? Changing type? |
34 |
|
35 |
assoc=(foo 'spam eggs') |
36 |
argv.py "${assoc[@]}" |
37 |
argv.py "${!assoc[@]}" |
38 |
|
39 |
## STDOUT: |
40 |
foo |
41 |
spam eggs |
42 |
k1 |
43 |
k2 |
44 |
['foo', 'spam eggs'] |
45 |
['0', '1'] |
46 |
## END |
47 |
## BUG bash STDOUT: |
48 |
foo |
49 |
spam eggs |
50 |
k1 |
51 |
k2 |
52 |
[] |
53 |
[] |
54 |
## END |
55 |
|
56 |
#### Can't initialize assoc array with indexed array |
57 |
declare -A A=(1 2 3) |
58 |
echo status=$? |
59 |
## STDOUT: |
60 |
status=2 |
61 |
## END |
62 |
|
63 |
# bash prints warnings to stderr but gives no indication of the problem |
64 |
## BUG bash STDOUT: |
65 |
status=0 |
66 |
## END |
67 |
|
68 |
|
69 |
#### Initializing indexed array with assoc array |
70 |
declare -a a=([xx]=1 [yy]=2 [zz]=3) |
71 |
echo status=$? |
72 |
argv.py "${a[@]}" |
73 |
## STDOUT: |
74 |
status=2 |
75 |
[] |
76 |
## END |
77 |
## BUG bash STDOUT: |
78 |
status=0 |
79 |
['3'] |
80 |
## END |
81 |
|
82 |
#### create empty assoc array, put, then get |
83 |
declare -A A # still undefined |
84 |
argv.py "${A[@]}" |
85 |
argv.py "${!A[@]}" |
86 |
A['foo']=bar |
87 |
echo ${A['foo']} |
88 |
## STDOUT: |
89 |
[] |
90 |
[] |
91 |
bar |
92 |
## END |
93 |
|
94 |
#### Empty value (doesn't use EmptyWord?) |
95 |
declare -A A=(["k"]= ) |
96 |
argv.py "${A["k"]}" |
97 |
## STDOUT: |
98 |
[''] |
99 |
## END |
100 |
|
101 |
#### retrieve keys with ! |
102 |
declare -A a |
103 |
var='x' |
104 |
a["$var"]=b |
105 |
a['foo']=bar |
106 |
a['a+1']=c |
107 |
for key in "${!a[@]}"; do |
108 |
echo $key |
109 |
done | sort |
110 |
## STDOUT: |
111 |
a+1 |
112 |
foo |
113 |
x |
114 |
## END |
115 |
|
116 |
#### retrieve values with ${A[@]} |
117 |
declare -A A |
118 |
var='x' |
119 |
A["$var"]=b |
120 |
A['foo']=bar |
121 |
A['a+1']=c |
122 |
for val in "${A[@]}"; do |
123 |
echo $val |
124 |
done | sort |
125 |
## STDOUT: |
126 |
b |
127 |
bar |
128 |
c |
129 |
## END |
130 |
|
131 |
#### coerce to string with ${A[*]}, etc. |
132 |
declare -A A |
133 |
A['X X']=xx |
134 |
A['Y Y']=yy |
135 |
argv.py "${A[*]}" |
136 |
argv.py "${!A[*]}" |
137 |
|
138 |
argv.py ${A[@]} |
139 |
argv.py ${!A[@]} |
140 |
## STDOUT: |
141 |
['xx yy'] |
142 |
['X X Y Y'] |
143 |
['xx', 'yy'] |
144 |
['X', 'X', 'Y', 'Y'] |
145 |
## END |
146 |
|
147 |
#### ${A[@]/b/B} |
148 |
# but ${!A[@]/b/B} doesn't work |
149 |
declare -A A |
150 |
A['aa']=bbb |
151 |
A['bb']=ccc |
152 |
A['cc']=ddd |
153 |
for val in "${A[@]//b/B}"; do |
154 |
echo $val |
155 |
done | sort |
156 |
## STDOUT: |
157 |
BBB |
158 |
ccc |
159 |
ddd |
160 |
## END |
161 |
|
162 |
#### ${A[@]#prefix} |
163 |
declare -A A |
164 |
A['aa']=one |
165 |
A['bb']=two |
166 |
A['cc']=three |
167 |
for val in "${A[@]#t}"; do |
168 |
echo $val |
169 |
done | sort |
170 |
## STDOUT: |
171 |
hree |
172 |
one |
173 |
wo |
174 |
## END |
175 |
|
176 |
#### ${assoc} is like ${assoc[0]} |
177 |
declare -A a |
178 |
|
179 |
a=([aa]=b [foo]=bar ['a+1']=c) |
180 |
echo a="${a}" |
181 |
|
182 |
a=([0]=zzz) |
183 |
echo a="${a}" |
184 |
|
185 |
a=(['0']=yyy) |
186 |
echo a="${a}" |
187 |
|
188 |
## STDOUT: |
189 |
a= |
190 |
a=zzz |
191 |
a=yyy |
192 |
## END |
193 |
|
194 |
#### length ${#a[@]} |
195 |
declare -A a |
196 |
a["x"]=1 |
197 |
a["y"]=2 |
198 |
a["z"]=3 |
199 |
echo "${#a[@]}" |
200 |
## stdout: 3 |
201 |
|
202 |
#### lookup with ${a[0]} -- "0" is a string |
203 |
declare -A a |
204 |
a["0"]=a |
205 |
a["1"]=b |
206 |
a["2"]=c |
207 |
echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}" |
208 |
## STDOUT: |
209 |
0 a 1 b 2 c |
210 |
## END |
211 |
|
212 |
#### lookup with double quoted strings "mykey" |
213 |
declare -A a |
214 |
a["aa"]=b |
215 |
a["foo"]=bar |
216 |
a['a+1']=c |
217 |
echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}" |
218 |
## STDOUT: |
219 |
b bar c |
220 |
## END |
221 |
|
222 |
#### lookup with single quoted string |
223 |
declare -A a |
224 |
a["aa"]=b |
225 |
a["foo"]=bar |
226 |
a['a+1']=c |
227 |
echo "${a['a+1']}" |
228 |
## stdout: c |
229 |
|
230 |
#### lookup with unquoted $key and quoted "$i$i" |
231 |
declare -A A |
232 |
A["aa"]=b |
233 |
A["foo"]=bar |
234 |
|
235 |
key=foo |
236 |
echo ${A[$key]} |
237 |
i=a |
238 |
echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH |
239 |
## STDOUT: |
240 |
bar |
241 |
b |
242 |
## END |
243 |
|
244 |
#### lookup by unquoted string doesn't work in OSH because it's a variable |
245 |
declare -A a |
246 |
a["aa"]=b |
247 |
a["foo"]=bar |
248 |
a['a+1']=c |
249 |
echo "${a[a+1]}" |
250 |
## stdout-json: "" |
251 |
## status: 1 |
252 |
## BUG bash stdout: c |
253 |
## BUG bash status: 0 |
254 |
|
255 |
#### bash bug: "i+1" and i+1 are the same key |
256 |
|
257 |
i=1 |
258 |
array=(5 6 7) |
259 |
echo array[i]="${array[i]}" |
260 |
echo array[i+1]="${array[i+1]}" |
261 |
|
262 |
# arithmetic does NOT work here in bash. These are unquoted strings! |
263 |
declare -A assoc |
264 |
assoc[i]=$i |
265 |
assoc[i+1]=$i+1 |
266 |
|
267 |
assoc["i"]=string |
268 |
assoc["i+1"]=string+1 |
269 |
|
270 |
echo assoc[i]="${assoc[i]}" |
271 |
echo assoc[i+1]="${assoc[i+1]}" |
272 |
|
273 |
echo assoc[i]="${assoc["i"]}" |
274 |
echo assoc[i+1]="${assoc["i+1"]}" |
275 |
|
276 |
## status: 1 |
277 |
## STDOUT: |
278 |
array[i]=6 |
279 |
array[i+1]=7 |
280 |
## END |
281 |
## BUG bash status: 0 |
282 |
## BUG bash STDOUT: |
283 |
array[i]=6 |
284 |
array[i+1]=7 |
285 |
assoc[i]=string |
286 |
assoc[i+1]=string+1 |
287 |
assoc[i]=string |
288 |
assoc[i+1]=string+1 |
289 |
## END |
290 |
|
291 |
#### Array stored in associative array gets converted to string (without strict_array) |
292 |
|
293 |
array=('1 2' 3) |
294 |
declare -A d |
295 |
d['key']="${array[@]}" |
296 |
argv.py "${d['key']}" |
297 |
## stdout: ['1 2 3'] |
298 |
|
299 |
#### Indexed array as key of associative array coerces to string (without shopt -s strict_array) |
300 |
|
301 |
declare -a array=(1 2 3) |
302 |
declare -A assoc |
303 |
assoc[42]=43 |
304 |
assoc["${array[@]}"]=foo |
305 |
|
306 |
echo "${assoc["${array[@]}"]}" |
307 |
for entry in "${!assoc[@]}"; do |
308 |
echo $entry |
309 |
done | sort |
310 |
|
311 |
## STDOUT: |
312 |
foo |
313 |
1 2 3 |
314 |
42 |
315 |
## END |
316 |
|
317 |
#### Append to associative array value A['x']+='suffix' |
318 |
declare -A A |
319 |
A['x']='foo' |
320 |
A['x']+='bar' |
321 |
A['x']+='bar' |
322 |
argv.py "${A["x"]}" |
323 |
## STDOUT: |
324 |
['foobarbar'] |
325 |
## END |
326 |
|
327 |
#### Slice of associative array doesn't make sense in bash |
328 |
declare -A a |
329 |
a[xx]=1 |
330 |
a[yy]=2 |
331 |
a[zz]=3 |
332 |
a[aa]=4 |
333 |
a[bb]=5 |
334 |
#argv.py ${a["xx"]} |
335 |
argv.py ${a[@]: 0: 3} |
336 |
argv.py ${a[@]: 1: 3} |
337 |
argv.py ${a[@]: 2: 3} |
338 |
argv.py ${a[@]: 3: 3} |
339 |
argv.py ${a[@]: 4: 3} |
340 |
argv.py ${a[@]: 5: 3} |
341 |
## stdout-json: "" |
342 |
## status: 1 |
343 |
## BUG bash STDOUT: |
344 |
['2', '1', '5'] |
345 |
['2', '1', '5'] |
346 |
['1', '5', '4'] |
347 |
['5', '4', '3'] |
348 |
['4', '3'] |
349 |
['3'] |
350 |
## END |
351 |
## BUG bash status: 0 |
352 |
|
353 |
#### bash variable can have an associative array part and a string part |
354 |
|
355 |
# and $assoc is equivalent to ${assoc[0]}, just like regular arrays |
356 |
declare -A assoc |
357 |
assoc[1]=1 |
358 |
assoc[2]=2 |
359 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
360 |
assoc[0]=zero |
361 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
362 |
assoc=string |
363 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
364 |
## STDOUT: |
365 |
1 2 |
366 |
1 2 zero |
367 |
1 2 string |
368 |
## END |
369 |
## N-I osh status: 1 |
370 |
## N-I osh STDOUT: |
371 |
1 2 |
372 |
1 2 zero |
373 |
## END |
374 |
|
375 |
#### Associative array expressions inside (( )) with keys that look like numbers |
376 |
declare -A assoc |
377 |
assoc[0]=42 |
378 |
(( var = ${assoc[0]} )) |
379 |
echo $var |
380 |
(( var = assoc[0] )) |
381 |
echo $var |
382 |
## STDOUT: |
383 |
42 |
384 |
42 |
385 |
## END |
386 |
|
387 |
#### (( A[5] += 42 )) |
388 |
declare -A A |
389 |
(( A[5] = 10 )) |
390 |
(( A[5] += 6 )) |
391 |
echo ${A[5]} |
392 |
## STDOUT: |
393 |
16 |
394 |
## END |
395 |
|
396 |
#### (( A[5] += 42 )) with empty cell |
397 |
shopt -u strict_arith # default zero cell |
398 |
declare -A A |
399 |
(( A[5] += 6 )) |
400 |
echo ${A[5]} |
401 |
## STDOUT: |
402 |
6 |
403 |
## END |
404 |
|
405 |
#### setting key to itself (from bash-bug mailing list) |
406 |
declare -A foo |
407 |
foo=(["key"]="value1") |
408 |
echo ${foo["key"]} |
409 |
foo=(["key"]="${foo["key"]} value2") |
410 |
echo ${foo["key"]} |
411 |
## STDOUT: |
412 |
value1 |
413 |
value1 value2 |
414 |
## END |
415 |
## BUG bash STDOUT: |
416 |
value1 |
417 |
value2 |
418 |
## END |
419 |
|
420 |
#### readonly associative array can't be modified |
421 |
declare -Ar A |
422 |
A['x']=1 |
423 |
echo status=$? |
424 |
## OK osh status: 1 |
425 |
## OK osh stdout-json: "" |
426 |
## STDOUT: |
427 |
status=1 |
428 |
## END |
429 |
|
430 |
#### associative array and brace expansion |
431 |
declare -A A=([k1]=v [k2]=-{a,b}-) |
432 |
echo ${A["k1"]} |
433 |
echo ${A["k2"]} |
434 |
## STDOUT: |
435 |
v |
436 |
-{a,b}- |
437 |
## END |
438 |
|
439 |
#### bash mangles array #1 |
440 |
a=([k1]=v1 [k2]=v2) |
441 |
echo ${a["k1"]} |
442 |
echo ${a["k2"]} |
443 |
## STDOUT: |
444 |
v1 |
445 |
v2 |
446 |
## END |
447 |
## BUG bash STDOUT: |
448 |
v2 |
449 |
v2 |
450 |
## END |
451 |
|
452 |
#### bash mangles array and brace #2 |
453 |
a=([k2]=-{a,b}-) |
454 |
echo ${a["k2"]} |
455 |
## STDOUT: |
456 |
-{a,b}- |
457 |
## END |
458 |
## BUG bash STDOUT: |
459 |
[k2]=-a- |
460 |
## END |
461 |
|
462 |
#### declare -A A=() alowed |
463 |
set -o nounset |
464 |
shopt -s strict_arith || true |
465 |
|
466 |
declare -A ASSOC=() |
467 |
echo len=${#ASSOC[@]} |
468 |
|
469 |
# Check that it really can be used like an associative array |
470 |
ASSOC['k']='32' |
471 |
echo len=${#ASSOC[@]} |
472 |
|
473 |
# bash allows a variable to be an associative array AND unset, while OSH |
474 |
# doesn't |
475 |
set +o nounset |
476 |
declare -A u |
477 |
echo unset len=${#u[@]} |
478 |
## STDOUT: |
479 |
len=0 |
480 |
len=1 |
481 |
unset len=0 |
482 |
## END |
483 |
|
484 |
#### unset -v and assoc array |
485 |
shopt -s eval_unsafe_arith || true |
486 |
|
487 |
show-len() { |
488 |
echo len=${#assoc[@]} |
489 |
} |
490 |
|
491 |
declare -A assoc=(['K']=val) |
492 |
show-len |
493 |
|
494 |
unset -v 'assoc["K"]' |
495 |
show-len |
496 |
|
497 |
declare -A assoc=(['K']=val) |
498 |
show-len |
499 |
key=K |
500 |
unset -v 'assoc[$key]' |
501 |
show-len |
502 |
|
503 |
declare -A assoc=(['K']=val) |
504 |
show-len |
505 |
unset -v 'assoc[$(echo K)]' |
506 |
show-len |
507 |
|
508 |
# ${prefix} doesn't work here, even though it does in arithmetic |
509 |
#declare -A assoc=(['K']=val) |
510 |
#show-len |
511 |
#prefix=as |
512 |
#unset -v '${prefix}soc[$key]' |
513 |
#show-len |
514 |
|
515 |
## STDOUT: |
516 |
len=1 |
517 |
len=0 |
518 |
len=1 |
519 |
len=0 |
520 |
len=1 |
521 |
len=0 |
522 |
## END |
523 |
|
524 |
#### nameref and assoc array |
525 |
show-values() { |
526 |
echo values: ${A[@]} |
527 |
} |
528 |
|
529 |
declare -A A=(['K']=val) |
530 |
show-values |
531 |
|
532 |
declare -n ref='A["K"]' |
533 |
echo before $ref |
534 |
ref='val2' |
535 |
echo after $ref |
536 |
show-values |
537 |
|
538 |
echo --- |
539 |
|
540 |
key=K |
541 |
declare -n ref='A[$key]' |
542 |
echo before $ref |
543 |
ref='val3' |
544 |
echo after $ref |
545 |
show-values |
546 |
|
547 |
## STDOUT: |
548 |
values: val |
549 |
before val |
550 |
after val2 |
551 |
values: val2 |
552 |
--- |
553 |
before val2 |
554 |
after val3 |
555 |
values: val3 |
556 |
## END |
557 |
|
558 |
#### ${!ref} and assoc array |
559 |
|
560 |
show-values() { |
561 |
echo values: ${A[@]} |
562 |
} |
563 |
|
564 |
declare -A A=(['K']=val) |
565 |
show-values |
566 |
|
567 |
declare ref='A["K"]' |
568 |
echo ref ${!ref} |
569 |
|
570 |
key=K |
571 |
declare ref='A[$key]' |
572 |
echo ref ${!ref} |
573 |
|
574 |
## STDOUT: |
575 |
values: val |
576 |
ref val |
577 |
ref val |
578 |
## END |
579 |
|
580 |
#### printf -v and assoc array |
581 |
|
582 |
show-values() { |
583 |
echo values: ${assoc[@]} |
584 |
} |
585 |
|
586 |
declare -A assoc=(['K']=val) |
587 |
show-values |
588 |
|
589 |
printf -v 'assoc["K"]' '/%s/' val2 |
590 |
show-values |
591 |
|
592 |
key=K |
593 |
printf -v 'assoc[$key]' '/%s/' val3 |
594 |
show-values |
595 |
|
596 |
# Somehow bash doesn't allow this |
597 |
#prefix=as |
598 |
#printf -v '${prefix}soc[$key]' '/%s/' val4 |
599 |
#show-values |
600 |
|
601 |
## STDOUT: |
602 |
values: val |
603 |
values: /val2/ |
604 |
values: /val3/ |
605 |
## END |
606 |
|
607 |
#### bash bug: (( A["$key"] = 1 )) doesn't work |
608 |
key='\' |
609 |
declare -A A |
610 |
#A["$key"]=1 |
611 |
|
612 |
# Works in both |
613 |
#A["$key"]=42 |
614 |
|
615 |
# Works in bash only |
616 |
#(( A[\$key] = 42 )) |
617 |
|
618 |
(( A["$key"] = 42 )) |
619 |
|
620 |
argv.py "${!A[@]}" |
621 |
argv.py "${A[@]}" |
622 |
## STDOUT: |
623 |
['\\'] |
624 |
['42'] |
625 |
## END |
626 |
## BUG bash STDOUT: |
627 |
[] |
628 |
[] |
629 |
## END |
630 |
|
631 |
|
632 |
#### Implicit increment of keys |
633 |
declare -a arr=( [30]=a b [40]=x y) |
634 |
argv.py "${!arr[@]}" |
635 |
argv.py "${arr[@]}" |
636 |
|
637 |
# osh says "expected associative array pair" |
638 |
|
639 |
## STDOUT: |
640 |
['30', '31', '40', '41'] |
641 |
['a', 'b', 'x', 'y'] |
642 |
## END |