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} disallowed in OSH, like ${assoc[0]} in bash |
177 |
declare -A a |
178 |
a=([aa]=b [foo]=bar ['a+1']=c) |
179 |
echo "${a}" |
180 |
## stdout-json: "\n" |
181 |
## OK osh stdout-json: "" |
182 |
## OK osh status: 1 |
183 |
|
184 |
#### length ${#a[@]} |
185 |
declare -A a |
186 |
a["x"]=1 |
187 |
a["y"]=2 |
188 |
a["z"]=3 |
189 |
echo "${#a[@]}" |
190 |
## stdout: 3 |
191 |
|
192 |
#### lookup with ${a[0]} -- "0" is a string |
193 |
declare -A a |
194 |
a["0"]=a |
195 |
a["1"]=b |
196 |
a["2"]=c |
197 |
echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}" |
198 |
## STDOUT: |
199 |
0 a 1 b 2 c |
200 |
## END |
201 |
|
202 |
#### lookup with double quoted strings "mykey" |
203 |
declare -A a |
204 |
a["aa"]=b |
205 |
a["foo"]=bar |
206 |
a['a+1']=c |
207 |
echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}" |
208 |
## STDOUT: |
209 |
b bar c |
210 |
## END |
211 |
|
212 |
#### lookup with single quoted string |
213 |
declare -A a |
214 |
a["aa"]=b |
215 |
a["foo"]=bar |
216 |
a['a+1']=c |
217 |
echo "${a['a+1']}" |
218 |
## stdout: c |
219 |
|
220 |
#### lookup with unquoted $key and quoted "$i$i" |
221 |
declare -A A |
222 |
A["aa"]=b |
223 |
A["foo"]=bar |
224 |
|
225 |
key=foo |
226 |
echo ${A[$key]} |
227 |
i=a |
228 |
echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH |
229 |
## STDOUT: |
230 |
bar |
231 |
b |
232 |
## END |
233 |
|
234 |
#### lookup by unquoted string doesn't work in OSH because it's a variable |
235 |
declare -A a |
236 |
a["aa"]=b |
237 |
a["foo"]=bar |
238 |
a['a+1']=c |
239 |
echo "${a[a+1]}" |
240 |
## stdout-json: "" |
241 |
## status: 1 |
242 |
## BUG bash stdout: c |
243 |
## BUG bash status: 0 |
244 |
|
245 |
#### bash bug: "i+1" and i+1 are the same key |
246 |
|
247 |
i=1 |
248 |
array=(5 6 7) |
249 |
echo array[i]="${array[i]}" |
250 |
echo array[i+1]="${array[i+1]}" |
251 |
|
252 |
# arithmetic does NOT work here in bash. These are unquoted strings! |
253 |
declare -A assoc |
254 |
assoc[i]=$i |
255 |
assoc[i+1]=$i+1 |
256 |
|
257 |
assoc["i"]=string |
258 |
assoc["i+1"]=string+1 |
259 |
|
260 |
echo assoc[i]="${assoc[i]}" |
261 |
echo assoc[i+1]="${assoc[i+1]}" |
262 |
|
263 |
echo assoc[i]="${assoc["i"]}" |
264 |
echo assoc[i+1]="${assoc["i+1"]}" |
265 |
|
266 |
## status: 1 |
267 |
## STDOUT: |
268 |
array[i]=6 |
269 |
array[i+1]=7 |
270 |
## END |
271 |
## BUG bash status: 0 |
272 |
## BUG bash STDOUT: |
273 |
array[i]=6 |
274 |
array[i+1]=7 |
275 |
assoc[i]=string |
276 |
assoc[i+1]=string+1 |
277 |
assoc[i]=string |
278 |
assoc[i+1]=string+1 |
279 |
## END |
280 |
|
281 |
#### Array stored in associative array gets converted to string (without strict_array) |
282 |
|
283 |
array=('1 2' 3) |
284 |
declare -A d |
285 |
d['key']="${array[@]}" |
286 |
argv.py "${d['key']}" |
287 |
## stdout: ['1 2 3'] |
288 |
|
289 |
#### Indexed array as key of associative array coerces to string (without shopt -s strict_array) |
290 |
|
291 |
declare -a array=(1 2 3) |
292 |
declare -A assoc |
293 |
assoc[42]=43 |
294 |
assoc["${array[@]}"]=foo |
295 |
|
296 |
echo "${assoc["${array[@]}"]}" |
297 |
for entry in "${!assoc[@]}"; do |
298 |
echo $entry |
299 |
done | sort |
300 |
|
301 |
## STDOUT: |
302 |
foo |
303 |
1 2 3 |
304 |
42 |
305 |
## END |
306 |
|
307 |
#### Append to associative array value A['x']+='suffix' |
308 |
declare -A A |
309 |
A['x']='foo' |
310 |
A['x']+='bar' |
311 |
A['x']+='bar' |
312 |
argv.py "${A["x"]}" |
313 |
## STDOUT: |
314 |
['foobarbar'] |
315 |
## END |
316 |
|
317 |
#### Slice of associative array doesn't make sense in bash |
318 |
declare -A a |
319 |
a[xx]=1 |
320 |
a[yy]=2 |
321 |
a[zz]=3 |
322 |
a[aa]=4 |
323 |
a[bb]=5 |
324 |
#argv.py ${a["xx"]} |
325 |
argv.py ${a[@]: 0: 3} |
326 |
argv.py ${a[@]: 1: 3} |
327 |
argv.py ${a[@]: 2: 3} |
328 |
argv.py ${a[@]: 3: 3} |
329 |
argv.py ${a[@]: 4: 3} |
330 |
argv.py ${a[@]: 5: 3} |
331 |
## stdout-json: "" |
332 |
## status: 1 |
333 |
## BUG bash STDOUT: |
334 |
['2', '1', '5'] |
335 |
['2', '1', '5'] |
336 |
['1', '5', '4'] |
337 |
['5', '4', '3'] |
338 |
['4', '3'] |
339 |
['3'] |
340 |
## END |
341 |
## BUG bash status: 0 |
342 |
|
343 |
#### bash variable can have an associative array part and a string part |
344 |
|
345 |
# and $assoc is equivalent to ${assoc[0]}, just like regular arrays |
346 |
declare -A assoc |
347 |
assoc[1]=1 |
348 |
assoc[2]=2 |
349 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
350 |
assoc[0]=zero |
351 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
352 |
assoc=string |
353 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
354 |
## STDOUT: |
355 |
1 2 |
356 |
1 2 zero |
357 |
1 2 string |
358 |
## END |
359 |
## N-I osh stdout-json: "" |
360 |
## N-I osh status: 1 |
361 |
|
362 |
#### Associative array expressions inside (( )) with keys that look like numbers |
363 |
declare -A assoc |
364 |
assoc[0]=42 |
365 |
(( var = ${assoc[0]} )) |
366 |
echo $var |
367 |
(( var = assoc[0] )) |
368 |
echo $var |
369 |
## STDOUT: |
370 |
42 |
371 |
42 |
372 |
## END |
373 |
|
374 |
#### (( A[5] += 42 )) |
375 |
declare -A A |
376 |
(( A[5] = 10 )) |
377 |
(( A[5] += 6 )) |
378 |
echo ${A[5]} |
379 |
## STDOUT: |
380 |
16 |
381 |
## END |
382 |
|
383 |
#### (( A[5] += 42 )) with empty cell |
384 |
shopt -u strict_arith # default zero cell |
385 |
declare -A A |
386 |
(( A[5] += 6 )) |
387 |
echo ${A[5]} |
388 |
## STDOUT: |
389 |
6 |
390 |
## END |
391 |
|
392 |
#### setting key to itself (from bash-bug mailing list) |
393 |
declare -A foo |
394 |
foo=(["key"]="value1") |
395 |
echo ${foo["key"]} |
396 |
foo=(["key"]="${foo["key"]} value2") |
397 |
echo ${foo["key"]} |
398 |
## STDOUT: |
399 |
value1 |
400 |
value1 value2 |
401 |
## END |
402 |
## BUG bash STDOUT: |
403 |
value1 |
404 |
value2 |
405 |
## END |
406 |
|
407 |
#### readonly associative array can't be modified |
408 |
declare -Ar A |
409 |
A['x']=1 |
410 |
echo status=$? |
411 |
## OK osh status: 1 |
412 |
## OK osh stdout-json: "" |
413 |
## STDOUT: |
414 |
status=1 |
415 |
## END |
416 |
|
417 |
#### associative array and brace expansion |
418 |
declare -A A=([k1]=v [k2]=-{a,b}-) |
419 |
echo ${A["k1"]} |
420 |
echo ${A["k2"]} |
421 |
## STDOUT: |
422 |
v |
423 |
-{a,b}- |
424 |
## END |
425 |
|
426 |
#### bash mangles array #1 |
427 |
a=([k1]=v1 [k2]=v2) |
428 |
echo ${a["k1"]} |
429 |
echo ${a["k2"]} |
430 |
## STDOUT: |
431 |
v1 |
432 |
v2 |
433 |
## END |
434 |
## BUG bash STDOUT: |
435 |
v2 |
436 |
v2 |
437 |
## END |
438 |
|
439 |
#### bash mangles array and brace #2 |
440 |
a=([k2]=-{a,b}-) |
441 |
echo ${a["k2"]} |
442 |
## STDOUT: |
443 |
-{a,b}- |
444 |
## END |
445 |
## BUG bash STDOUT: |
446 |
[k2]=-a- |
447 |
## END |
448 |
|
449 |
#### declare -A A=() alowed |
450 |
set -o nounset |
451 |
shopt -s strict_arith || true |
452 |
|
453 |
declare -A ASSOC=() |
454 |
echo len=${#ASSOC[@]} |
455 |
|
456 |
# Check that it really can be used like an associative array |
457 |
ASSOC['k']='32' |
458 |
echo len=${#ASSOC[@]} |
459 |
|
460 |
# bash allows a variable to be an associative array AND unset, while OSH |
461 |
# doesn't |
462 |
set +o nounset |
463 |
declare -A u |
464 |
echo unset len=${#u[@]} |
465 |
## STDOUT: |
466 |
len=0 |
467 |
len=1 |
468 |
unset len=0 |
469 |
## END |
470 |
|
471 |
#### unset -v and assoc array |
472 |
shopt -s eval_unsafe_arith || true |
473 |
|
474 |
show-len() { |
475 |
echo len=${#assoc[@]} |
476 |
} |
477 |
|
478 |
declare -A assoc=(['K']=val) |
479 |
show-len |
480 |
|
481 |
unset -v 'assoc["K"]' |
482 |
show-len |
483 |
|
484 |
declare -A assoc=(['K']=val) |
485 |
show-len |
486 |
key=K |
487 |
unset -v 'assoc[$key]' |
488 |
show-len |
489 |
|
490 |
declare -A assoc=(['K']=val) |
491 |
show-len |
492 |
unset -v 'assoc[$(echo K)]' |
493 |
show-len |
494 |
|
495 |
# ${prefix} doesn't work here, even though it does in arithmetic |
496 |
#declare -A assoc=(['K']=val) |
497 |
#show-len |
498 |
#prefix=as |
499 |
#unset -v '${prefix}soc[$key]' |
500 |
#show-len |
501 |
|
502 |
## STDOUT: |
503 |
len=1 |
504 |
len=0 |
505 |
len=1 |
506 |
len=0 |
507 |
len=1 |
508 |
len=0 |
509 |
## END |
510 |
|
511 |
#### nameref and assoc array |
512 |
show-values() { |
513 |
echo values: ${A[@]} |
514 |
} |
515 |
|
516 |
declare -A A=(['K']=val) |
517 |
show-values |
518 |
|
519 |
declare -n ref='A["K"]' |
520 |
echo before $ref |
521 |
ref='val2' |
522 |
echo after $ref |
523 |
show-values |
524 |
|
525 |
echo --- |
526 |
|
527 |
key=K |
528 |
declare -n ref='A[$key]' |
529 |
echo before $ref |
530 |
ref='val3' |
531 |
echo after $ref |
532 |
show-values |
533 |
|
534 |
## STDOUT: |
535 |
values: val |
536 |
before val |
537 |
after val2 |
538 |
values: val2 |
539 |
--- |
540 |
before val2 |
541 |
after val3 |
542 |
values: val3 |
543 |
## END |
544 |
|
545 |
#### ${!ref} and assoc array |
546 |
shopt -s eval_unsafe_arith |
547 |
|
548 |
show-values() { |
549 |
echo values: ${A[@]} |
550 |
} |
551 |
|
552 |
declare -A A=(['K']=val) |
553 |
show-values |
554 |
|
555 |
declare ref='A["K"]' |
556 |
echo ref ${!ref} |
557 |
|
558 |
key=K |
559 |
declare ref='A[$key]' |
560 |
echo ref ${!ref} |
561 |
|
562 |
## STDOUT: |
563 |
values: val |
564 |
ref val |
565 |
ref val |
566 |
## END |
567 |
|
568 |
#### printf -v and assoc array |
569 |
shopt -s eval_unsafe_arith |
570 |
|
571 |
show-values() { |
572 |
echo values: ${assoc[@]} |
573 |
} |
574 |
|
575 |
declare -A assoc=(['K']=val) |
576 |
show-values |
577 |
|
578 |
printf -v 'assoc["K"]' '/%s/' val2 |
579 |
show-values |
580 |
|
581 |
key=K |
582 |
printf -v 'assoc[$key]' '/%s/' val3 |
583 |
show-values |
584 |
|
585 |
# Somehow bash doesn't allow this |
586 |
#prefix=as |
587 |
#printf -v '${prefix}soc[$key]' '/%s/' val4 |
588 |
#show-values |
589 |
|
590 |
## STDOUT: |
591 |
values: val |
592 |
values: /val2/ |
593 |
values: /val3/ |
594 |
## END |
595 |
|
596 |
#### bash bug: (( A["$key"] = 1 )) doesn't work |
597 |
key='\' |
598 |
declare -A A |
599 |
#A["$key"]=1 |
600 |
|
601 |
# Works in both |
602 |
#A["$key"]=42 |
603 |
|
604 |
# Works in bash only |
605 |
#(( A[\$key] = 42 )) |
606 |
|
607 |
(( A["$key"] = 42 )) |
608 |
|
609 |
argv.py "${!A[@]}" |
610 |
argv.py "${A[@]}" |
611 |
## STDOUT: |
612 |
['\\'] |
613 |
['42'] |
614 |
## END |
615 |
## BUG bash STDOUT: |
616 |
[] |
617 |
[] |
618 |
## END |
619 |
|
620 |
|
621 |
#### Implicit increment of keys |
622 |
declare -a arr=( [30]=a b [40]=x y) |
623 |
argv.py "${!arr[@]}" |
624 |
argv.py "${arr[@]}" |
625 |
|
626 |
# osh says "expected associative array pair" |
627 |
|
628 |
## STDOUT: |
629 |
['30', '31', '40', '41'] |
630 |
['a', 'b', 'x', 'y'] |
631 |
## END |