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