1 #!/usr/bin/env bash
2
3 # NOTE:
4 # -declare -A is required.
5 #
6 # Simply doing:
7 # a=([aa]=b [foo]=bar ['a+1']=c)
8 # gets utterly bizarre behavior.
9 #
10 # Associtative Arrays are COMPLETELY bash-specific. mksh doesn't even come
11 # close. So I will probably not implement them, or implement something
12 # slightly different, because the semantics are just wierd.
13
14 # http://www.gnu.org/software/bash/manual/html_node/Arrays.html
15 # TODO: Need a SETUP section.
16
17 #### Literal syntax ([x]=y)
18 declare -A a
19 a=([aa]=b [foo]=bar ['a+1']=c)
20 echo ${a["aa"]}
21 echo ${a["foo"]}
22 echo ${a["a+1"]}
23 ## STDOUT:
24 b
25 bar
26 c
27 ## END
28
29 #### set associative array to indexed array literal (very surprising bash behavior)
30 declare -A assoc=([k1]=foo [k2]='spam eggs')
31 for v in "${assoc[@]}"; do echo $v; done | sort
32 for v in "${!assoc[@]}"; do echo $v; done | sort
33
34 # disallow this in OSH? Changing type?
35
36 assoc=(foo 'spam eggs')
37 argv.py "${assoc[@]}"
38 argv.py "${!assoc[@]}"
39
40 ## STDOUT:
41 foo
42 spam eggs
43 k1
44 k2
45 ['foo', 'spam eggs']
46 ['0', '1']
47 ## END
48 ## BUG bash STDOUT:
49 foo
50 spam eggs
51 k1
52 k2
53 []
54 []
55 ## END
56
57 #### Can't initialize assoc array with indexed array
58 declare -A A=(1 2 3)
59 echo status=$?
60 ## STDOUT:
61 status=1
62 ## END
63
64 # bash prints warnings to stderr but gives no indication of the problem
65 ## BUG bash STDOUT:
66 status=0
67 ## END
68
69
70 #### Initializing indexed array with assoc array
71 declare -a a=([xx]=1 [yy]=2 [zz]=3)
72 echo status=$?
73 argv.py "${a[@]}"
74 ## STDOUT:
75 status=1
76 []
77 ## END
78 ## BUG bash STDOUT:
79 status=0
80 ['3']
81 ## END
82
83 #### create empty assoc array, put, then get
84 declare -A A # still undefined
85 argv.py "${A[@]}"
86 argv.py "${!A[@]}"
87 A['foo']=bar
88 echo ${A['foo']}
89 ## STDOUT:
90 []
91 []
92 bar
93 ## END
94
95 #### Empty value (doesn't use EmptyWord?)
96 declare -A A=(["k"]= )
97 argv.py "${A["k"]}"
98 ## STDOUT:
99 ['']
100 ## END
101
102 #### retrieve keys with !
103 declare -A a
104 var='x'
105 a["$var"]=b
106 a['foo']=bar
107 a['a+1']=c
108 for key in "${!a[@]}"; do
109 echo $key
110 done | sort
111 ## STDOUT:
112 a+1
113 foo
114 x
115 ## END
116
117 #### retrieve values with ${A[@]}
118 declare -A A
119 var='x'
120 A["$var"]=b
121 A['foo']=bar
122 A['a+1']=c
123 for val in "${A[@]}"; do
124 echo $val
125 done | sort
126 ## STDOUT:
127 b
128 bar
129 c
130 ## END
131
132 #### coerce to string with ${A[*]}, etc.
133 declare -A A
134 A['X X']=xx
135 A['Y Y']=yy
136 argv.py "${A[*]}"
137 argv.py "${!A[*]}"
138
139 argv.py ${A[@]}
140 argv.py ${!A[@]}
141 ## STDOUT:
142 ['xx yy']
143 ['X X Y Y']
144 ['xx', 'yy']
145 ['X', 'X', 'Y', 'Y']
146 ## END
147
148 #### ${A[@]/b/B}
149 # but ${!A[@]/b/B} doesn't work
150 declare -A A
151 A['aa']=bbb
152 A['bb']=ccc
153 A['cc']=ddd
154 for val in "${A[@]//b/B}"; do
155 echo $val
156 done | sort
157 ## STDOUT:
158 BBB
159 ccc
160 ddd
161 ## END
162
163 #### ${A[@]#prefix}
164 declare -A A
165 A['aa']=one
166 A['bb']=two
167 A['cc']=three
168 for val in "${A[@]#t}"; do
169 echo $val
170 done | sort
171 ## STDOUT:
172 hree
173 one
174 wo
175 ## END
176
177 #### ${assoc} disallowed in OSH, like ${assoc[0]} in bash
178 declare -A a
179 a=([aa]=b [foo]=bar ['a+1']=c)
180 echo "${a}"
181 ## stdout-json: "\n"
182 ## OK osh stdout-json: ""
183 ## OK osh status: 1
184
185 #### length ${#a[@]}
186 declare -A a
187 a["x"]=1
188 a["y"]=2
189 a["z"]=3
190 echo "${#a[@]}"
191 ## stdout: 3
192
193 #### lookup with ${a[0]} -- "0" is a string
194 declare -A a
195 a["0"]=a
196 a["1"]=b
197 a["2"]=c
198 echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}"
199 ## STDOUT:
200 0 a 1 b 2 c
201 ## END
202
203 #### lookup with double quoted strings "mykey"
204 declare -A a
205 a["aa"]=b
206 a["foo"]=bar
207 a['a+1']=c
208 echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}"
209 ## STDOUT:
210 b bar c
211 ## END
212
213 #### lookup with single quoted string
214 declare -A a
215 a["aa"]=b
216 a["foo"]=bar
217 a['a+1']=c
218 echo "${a['a+1']}"
219 ## stdout: c
220
221 #### lookup with unquoted $key and quoted "$i$i"
222 declare -A A
223 A["aa"]=b
224 A["foo"]=bar
225
226 key=foo
227 echo ${A[$key]}
228 i=a
229 echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH
230 ## STDOUT:
231 bar
232 b
233 ## END
234
235 #### lookup by unquoted string doesn't work in OSH because it's a variable
236 declare -A a
237 a["aa"]=b
238 a["foo"]=bar
239 a['a+1']=c
240 echo "${a[a+1]}"
241 ## stdout-json: ""
242 ## status: 1
243 ## BUG bash stdout: c
244 ## BUG bash status: 0
245
246 #### bash bug: "i+1" and i+1 are the same key
247
248 i=1
249 array=(5 6 7)
250 echo array[i]="${array[i]}"
251 echo array[i+1]="${array[i+1]}"
252
253 # arithmetic does NOT work here in bash. These are unquoted strings!
254 declare -A assoc
255 assoc[i]=$i
256 assoc[i+1]=$i+1
257
258 assoc["i"]=string
259 assoc["i+1"]=string+1
260
261 echo assoc[i]="${assoc[i]}"
262 echo assoc[i+1]="${assoc[i+1]}"
263
264 echo assoc[i]="${assoc["i"]}"
265 echo assoc[i+1]="${assoc["i+1"]}"
266
267 ## status: 1
268 ## STDOUT:
269 array[i]=6
270 array[i+1]=7
271 ## END
272 ## BUG bash status: 0
273 ## BUG bash STDOUT:
274 array[i]=6
275 array[i+1]=7
276 assoc[i]=string
277 assoc[i+1]=string+1
278 assoc[i]=string
279 assoc[i+1]=string+1
280 ## END
281
282 #### Array stored in associative array gets converted to string (without strict_array)
283
284 array=('1 2' 3)
285 declare -A d
286 d['key']="${array[@]}"
287 argv.py "${d['key']}"
288 ## stdout: ['1 2 3']
289
290 #### Indexed array as key of associative array coerces to string (without shopt -s strict_array)
291
292 declare -a array=(1 2 3)
293 declare -A assoc
294 assoc[42]=43
295 assoc["${array[@]}"]=foo
296
297 echo "${assoc["${array[@]}"]}"
298 for entry in "${!assoc[@]}"; do
299 echo $entry
300 done | sort
301
302 ## STDOUT:
303 foo
304 1 2 3
305 42
306 ## END
307
308 #### Append to associative array value A['x']+='suffix'
309 declare -A A
310 A['x']='foo'
311 A['x']+='bar'
312 A['x']+='bar'
313 argv.py "${A["x"]}"
314 ## STDOUT:
315 ['foobarbar']
316 ## END
317
318 #### Slice of associative array doesn't make sense in bash
319 declare -A a
320 a[xx]=1
321 a[yy]=2
322 a[zz]=3
323 a[aa]=4
324 a[bb]=5
325 #argv.py ${a["xx"]}
326 argv.py ${a[@]: 0: 3}
327 argv.py ${a[@]: 1: 3}
328 argv.py ${a[@]: 2: 3}
329 argv.py ${a[@]: 3: 3}
330 argv.py ${a[@]: 4: 3}
331 argv.py ${a[@]: 5: 3}
332 ## stdout-json: ""
333 ## status: 1
334 ## BUG bash STDOUT:
335 ['2', '1', '5']
336 ['2', '1', '5']
337 ['1', '5', '4']
338 ['5', '4', '3']
339 ['4', '3']
340 ['3']
341 ## END
342 ## BUG bash status: 0
343
344 #### bash variable can have an associative array part and a string part
345
346 # and $assoc is equivalent to ${assoc[0]}, just like regular arrays
347 declare -A assoc
348 assoc[1]=1
349 assoc[2]=2
350 echo ${assoc[1]} ${assoc[2]} ${assoc}
351 assoc[0]=zero
352 echo ${assoc[1]} ${assoc[2]} ${assoc}
353 assoc=string
354 echo ${assoc[1]} ${assoc[2]} ${assoc}
355 ## STDOUT:
356 1 2
357 1 2 zero
358 1 2 string
359 ## END
360 ## N-I osh stdout-json: ""
361 ## N-I osh status: 1
362
363 #### Associative array expressions inside (( )) with keys that look like numbers
364 declare -A assoc
365 assoc[0]=42
366 (( var = ${assoc[0]} ))
367 echo $var
368 (( var = assoc[0] ))
369 echo $var
370 ## STDOUT:
371 42
372 42
373 ## END
374 ## N-I osh status: 1
375 ## N-I osh STDOUT:
376 42
377 ## END
378
379 #### (( A[5] += 42 ))
380 declare -A A
381 (( A[5] = 10 ))
382 (( A[5] += 6 ))
383 echo ${A[5]}
384 ## STDOUT:
385 16
386 ## END
387
388 #### (( A[5] += 42 )) with empty cell
389 shopt -u strict_arith # default zero cell
390 declare -A A
391 (( A[5] += 6 ))
392 echo ${A[5]}
393 ## STDOUT:
394 6
395 ## END
396
397 #### setting key to itself (from bash-bug mailing list)
398 declare -A foo
399 foo=(["key"]="value1")
400 echo ${foo["key"]}
401 foo=(["key"]="${foo["key"]} value2")
402 echo ${foo["key"]}
403 ## STDOUT:
404 value1
405 value1 value2
406 ## END
407 ## BUG bash STDOUT:
408 value1
409 value2
410 ## END
411
412 #### readonly associative array can't be modified
413 declare -Ar A
414 A['x']=1
415 echo status=$?
416 ## OK osh status: 1
417 ## OK osh stdout-json: ""
418 ## STDOUT:
419 status=1
420 ## END
421
422 #### associative array and brace expansion
423 declare -A A=([k1]=v [k2]=-{a,b}-)
424 echo ${A["k1"]}
425 echo ${A["k2"]}
426 ## STDOUT:
427 v
428 -{a,b}-
429 ## END
430
431 #### bash mangles array #1
432 a=([k1]=v1 [k2]=v2)
433 echo ${a["k1"]}
434 echo ${a["k2"]}
435 ## STDOUT:
436 v1
437 v2
438 ## END
439 ## BUG bash STDOUT:
440 v2
441 v2
442 ## END
443
444 #### bash mangles array and brace #2
445 a=([k2]=-{a,b}-)
446 echo ${a["k2"]}
447 ## STDOUT:
448 -{a,b}-
449 ## END
450 ## BUG bash STDOUT:
451 [k2]=-a-
452 ## END
453