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 (bash anomaly)
30 declare -A assoc=([k1]=foo [k2]='spam eggs')
31 argv.py "${assoc[@]}"
32 argv.py "${!assoc[@]}"
33
34 # shouldn't this be disallowed? You're losing information.
35
36 assoc=(foo 'spam eggs')
37 argv.py "${assoc[@]}"
38 argv.py "${!assoc[@]}"
39
40 ## STDOUT:
41 ['foo', 'spam eggs']
42 ['k1', 'k2']
43 []
44 []
45 ## END
46
47 #### Can't initialize assoc array with indexed array
48 declare -A A=(1 2 3)
49 ## status: 1
50 ## BUG bash status: 0
51
52 #### Initializing indexed array with assoc array
53 declare -a a=([xx]=1 [yy]=2 [zz]=3)
54 #declare -a a=(1 2 3)
55 argv.py "${a[@]}"
56 ## status: 1
57 ## stdout-json: ""
58 ## BUG bash status: 0
59 ## BUG bash STDOUT:
60 ['3']
61 ## END
62
63 #### create empty assoc array, put, then get
64 declare -A A # still undefined
65 argv.py "${A[@]}"
66 argv.py "${!A[@]}"
67 A['foo']=bar
68 echo ${A['foo']}
69 ## STDOUT:
70 []
71 []
72 bar
73 ## END
74
75 #### retrieve keys with !
76 declare -A a
77 var='x'
78 a["$var"]=b
79 a['foo']=bar
80 a['a+1']=c
81 for key in "${!a[@]}"; do
82 echo $key
83 done | sort
84 ## STDOUT:
85 a+1
86 foo
87 x
88 ## END
89
90 #### retrieve values with ${A[@]}
91 declare -A A
92 var='x'
93 A["$var"]=b
94 A['foo']=bar
95 A['a+1']=c
96 for val in "${A[@]}"; do
97 echo $val
98 done | sort
99 ## STDOUT:
100 b
101 bar
102 c
103 ## END
104
105 #### coerce to string with ${A[*]}, etc.
106 declare -A A
107 A['X X']=xx
108 A['Y Y']=yy
109 argv.py "${A[*]}"
110 argv.py "${!A[*]}"
111
112 argv.py ${A[@]}
113 argv.py ${!A[@]}
114 ## STDOUT:
115 ['xx yy']
116 ['X X Y Y']
117 ['xx', 'yy']
118 ['X', 'X', 'Y', 'Y']
119 ## END
120
121 #### ${A[@]/b/B}
122 # but ${!A[@]/b/B} doesn't work
123 declare -A A
124 A['aa']=bbb
125 A['bb']=ccc
126 A['cc']=ddd
127 for val in "${A[@]//b/B}"; do
128 echo $val
129 done | sort
130 ## STDOUT:
131 BBB
132 ccc
133 ddd
134 ## END
135
136 #### ${A[@]#prefix}
137 declare -A A
138 A['aa']=one
139 A['bb']=two
140 A['cc']=three
141 for val in "${A[@]#t}"; do
142 echo $val
143 done | sort
144 ## STDOUT:
145 hree
146 one
147 wo
148 ## END
149
150 #### ${assoc} disallowed in OSH, like ${assoc[0]} in bash
151 declare -A a
152 a=([aa]=b [foo]=bar ['a+1']=c)
153 echo "${a}"
154 ## stdout-json: "\n"
155 ## OK osh stdout-json: ""
156 ## OK osh status: 1
157
158 #### length ${#a[@]}
159 declare -A a
160 a["x"]=1
161 a["y"]=2
162 a["z"]=3
163 echo "${#a[@]}"
164 ## stdout: 3
165
166 #### lookup with ${a[0]} -- "0" is a string
167 declare -A a
168 a["0"]=a
169 a["1"]=b
170 a["2"]=c
171 echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}"
172 ## STDOUT:
173 0 a 1 b 2 c
174 ## END
175
176 #### lookup with double quoted strings "mykey"
177 declare -A a
178 a["aa"]=b
179 a["foo"]=bar
180 a['a+1']=c
181 echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}"
182 ## STDOUT:
183 b bar c
184 ## END
185
186 #### lookup with single quoted string
187 declare -A a
188 a["aa"]=b
189 a["foo"]=bar
190 a['a+1']=c
191 echo "${a['a+1']}"
192 ## stdout: c
193
194 #### lookup with unquoted $key and quoted "$i$i"
195 declare -A A
196 A["aa"]=b
197 A["foo"]=bar
198
199 key=foo
200 echo ${A[$key]}
201 i=a
202 echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH
203 ## STDOUT:
204 bar
205 b
206 ## END
207
208 #### lookup by unquoted string doesn't work in OSH because it's a variable
209 declare -A a
210 a["aa"]=b
211 a["foo"]=bar
212 a['a+1']=c
213 echo "${a[a+1]}"
214 ## stdout-json: ""
215 ## status: 1
216 ## BUG bash stdout: c
217 ## BUG bash status: 0
218
219 #### bash bug: "i+1" and i+1 are the same key
220
221 i=1
222 array=(5 6 7)
223 echo array[i]="${array[i]}"
224 echo array[i+1]="${array[i+1]}"
225
226 # arithmetic does NOT work here in bash. These are unquoted strings!
227 declare -A assoc
228 assoc[i]=$i
229 assoc[i+1]=$i+1
230
231 assoc["i"]=string
232 assoc["i+1"]=string+1
233
234 echo assoc[i]="${assoc[i]}"
235 echo assoc[i+1]="${assoc[i+1]}"
236
237 echo assoc[i]="${assoc["i"]}"
238 echo assoc[i+1]="${assoc["i+1"]}"
239
240 ## status: 1
241 ## STDOUT:
242 array[i]=6
243 array[i+1]=7
244 ## END
245 ## BUG bash status: 0
246 ## BUG bash STDOUT:
247 array[i]=6
248 array[i+1]=7
249 assoc[i]=string
250 assoc[i+1]=string+1
251 assoc[i]=string
252 assoc[i+1]=string+1
253 ## END
254
255 #### Array stored in associative array gets converted to string (without strict-array)
256
257 array=('1 2' 3)
258 declare -A d
259 d['key']="${array[@]}"
260 argv.py "${d['key']}"
261 ## stdout: ['1 2 3']
262
263 #### Indexed array as key of associative array coerces to string (without shopt -s strict-array)
264
265 declare -a array=(1 2 3)
266 declare -A assoc
267 assoc[42]=43
268 assoc["${array[@]}"]=foo
269
270 echo "${assoc["${array[@]}"]}"
271 for entry in "${!assoc[@]}"; do
272 echo $entry
273 done | sort
274
275 ## STDOUT:
276 foo
277 1 2 3
278 42
279 ##
280
281 #### Append to associative array value A['x']+='suffix'
282 declare -A A
283 A['x']='foo'
284 A['x']+='bar'
285 A['x']+='bar'
286 argv.py "${A["x"]}"
287 ## STDOUT:
288 ['foobarbar']
289 ## END
290
291 #### Slice of associative array doesn't make sense in bash
292 declare -A a
293 a[xx]=1
294 a[yy]=2
295 a[zz]=3
296 a[aa]=4
297 a[bb]=5
298 #argv.py ${a["xx"]}
299 argv.py ${a[@]: 0: 3}
300 argv.py ${a[@]: 1: 3}
301 argv.py ${a[@]: 2: 3}
302 argv.py ${a[@]: 3: 3}
303 argv.py ${a[@]: 4: 3}
304 argv.py ${a[@]: 5: 3}
305 ## stdout-json: ""
306 ## status: 1
307 ## BUG bash STDOUT:
308 ['2', '1', '5']
309 ['2', '1', '5']
310 ['1', '5', '4']
311 ['5', '4', '3']
312 ['4', '3']
313 ['3']
314 ## END
315 ## BUG bash status: 0
316
317 #### bash variable can have an associative array part and a string part
318
319 # and $assoc is equivalent to ${assoc[0]}, just like regular arrays
320 declare -A assoc
321 assoc[1]=1
322 assoc[2]=2
323 echo ${assoc[1]} ${assoc[2]} ${assoc}
324 assoc[0]=zero
325 echo ${assoc[1]} ${assoc[2]} ${assoc}
326 assoc=string
327 echo ${assoc[1]} ${assoc[2]} ${assoc}
328 ## STDOUT:
329 1 2
330 1 2 zero
331 1 2 string
332 ## END
333 ## N-I osh stdout-json: ""
334 ## N-I osh status: 1
335
336 #### Associative array expressions inside (( )) with keys that look like numbers
337 declare -A assoc
338 assoc[0]=42
339 (( var = ${assoc[0]} ))
340 echo $var
341 (( var = assoc[0] ))
342 echo $var
343 ## STDOUT:
344 42
345 42
346 ## END
347 ## N-I osh status: 1
348 ## N-I osh STDOUT:
349 42
350 ## END
351
352 #### (( A[5] += 42 ))
353 declare -A A
354 (( A[5] = 10 ))
355 (( A[5] += 6 ))
356 echo ${A[5]}
357 ## STDOUT:
358 16
359 ## END
360
361 #### (( A[5] += 42 )) with empty cell
362 shopt -u strict-arith # default zero cell
363 declare -A A
364 (( A[5] += 6 ))
365 echo ${A[5]}
366 ## STDOUT:
367 6
368 ## END