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 |
#### retrieve keys with ! |
96 |
declare -A a |
97 |
var='x' |
98 |
a["$var"]=b |
99 |
a['foo']=bar |
100 |
a['a+1']=c |
101 |
for key in "${!a[@]}"; do |
102 |
echo $key |
103 |
done | sort |
104 |
## STDOUT: |
105 |
a+1 |
106 |
foo |
107 |
x |
108 |
## END |
109 |
|
110 |
#### retrieve values with ${A[@]} |
111 |
declare -A A |
112 |
var='x' |
113 |
A["$var"]=b |
114 |
A['foo']=bar |
115 |
A['a+1']=c |
116 |
for val in "${A[@]}"; do |
117 |
echo $val |
118 |
done | sort |
119 |
## STDOUT: |
120 |
b |
121 |
bar |
122 |
c |
123 |
## END |
124 |
|
125 |
#### coerce to string with ${A[*]}, etc. |
126 |
declare -A A |
127 |
A['X X']=xx |
128 |
A['Y Y']=yy |
129 |
argv.py "${A[*]}" |
130 |
argv.py "${!A[*]}" |
131 |
|
132 |
argv.py ${A[@]} |
133 |
argv.py ${!A[@]} |
134 |
## STDOUT: |
135 |
['xx yy'] |
136 |
['X X Y Y'] |
137 |
['xx', 'yy'] |
138 |
['X', 'X', 'Y', 'Y'] |
139 |
## END |
140 |
|
141 |
#### ${A[@]/b/B} |
142 |
# but ${!A[@]/b/B} doesn't work |
143 |
declare -A A |
144 |
A['aa']=bbb |
145 |
A['bb']=ccc |
146 |
A['cc']=ddd |
147 |
for val in "${A[@]//b/B}"; do |
148 |
echo $val |
149 |
done | sort |
150 |
## STDOUT: |
151 |
BBB |
152 |
ccc |
153 |
ddd |
154 |
## END |
155 |
|
156 |
#### ${A[@]#prefix} |
157 |
declare -A A |
158 |
A['aa']=one |
159 |
A['bb']=two |
160 |
A['cc']=three |
161 |
for val in "${A[@]#t}"; do |
162 |
echo $val |
163 |
done | sort |
164 |
## STDOUT: |
165 |
hree |
166 |
one |
167 |
wo |
168 |
## END |
169 |
|
170 |
#### ${assoc} disallowed in OSH, like ${assoc[0]} in bash |
171 |
declare -A a |
172 |
a=([aa]=b [foo]=bar ['a+1']=c) |
173 |
echo "${a}" |
174 |
## stdout-json: "\n" |
175 |
## OK osh stdout-json: "" |
176 |
## OK osh status: 1 |
177 |
|
178 |
#### length ${#a[@]} |
179 |
declare -A a |
180 |
a["x"]=1 |
181 |
a["y"]=2 |
182 |
a["z"]=3 |
183 |
echo "${#a[@]}" |
184 |
## stdout: 3 |
185 |
|
186 |
#### lookup with ${a[0]} -- "0" is a string |
187 |
declare -A a |
188 |
a["0"]=a |
189 |
a["1"]=b |
190 |
a["2"]=c |
191 |
echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}" |
192 |
## STDOUT: |
193 |
0 a 1 b 2 c |
194 |
## END |
195 |
|
196 |
#### lookup with double quoted strings "mykey" |
197 |
declare -A a |
198 |
a["aa"]=b |
199 |
a["foo"]=bar |
200 |
a['a+1']=c |
201 |
echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}" |
202 |
## STDOUT: |
203 |
b bar c |
204 |
## END |
205 |
|
206 |
#### lookup with single quoted string |
207 |
declare -A a |
208 |
a["aa"]=b |
209 |
a["foo"]=bar |
210 |
a['a+1']=c |
211 |
echo "${a['a+1']}" |
212 |
## stdout: c |
213 |
|
214 |
#### lookup with unquoted $key and quoted "$i$i" |
215 |
declare -A A |
216 |
A["aa"]=b |
217 |
A["foo"]=bar |
218 |
|
219 |
key=foo |
220 |
echo ${A[$key]} |
221 |
i=a |
222 |
echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH |
223 |
## STDOUT: |
224 |
bar |
225 |
b |
226 |
## END |
227 |
|
228 |
#### lookup by unquoted string doesn't work in OSH because it's a variable |
229 |
declare -A a |
230 |
a["aa"]=b |
231 |
a["foo"]=bar |
232 |
a['a+1']=c |
233 |
echo "${a[a+1]}" |
234 |
## stdout-json: "" |
235 |
## status: 1 |
236 |
## BUG bash stdout: c |
237 |
## BUG bash status: 0 |
238 |
|
239 |
#### bash bug: "i+1" and i+1 are the same key |
240 |
|
241 |
i=1 |
242 |
array=(5 6 7) |
243 |
echo array[i]="${array[i]}" |
244 |
echo array[i+1]="${array[i+1]}" |
245 |
|
246 |
# arithmetic does NOT work here in bash. These are unquoted strings! |
247 |
declare -A assoc |
248 |
assoc[i]=$i |
249 |
assoc[i+1]=$i+1 |
250 |
|
251 |
assoc["i"]=string |
252 |
assoc["i+1"]=string+1 |
253 |
|
254 |
echo assoc[i]="${assoc[i]}" |
255 |
echo assoc[i+1]="${assoc[i+1]}" |
256 |
|
257 |
echo assoc[i]="${assoc["i"]}" |
258 |
echo assoc[i+1]="${assoc["i+1"]}" |
259 |
|
260 |
## status: 1 |
261 |
## STDOUT: |
262 |
array[i]=6 |
263 |
array[i+1]=7 |
264 |
## END |
265 |
## BUG bash status: 0 |
266 |
## BUG bash STDOUT: |
267 |
array[i]=6 |
268 |
array[i+1]=7 |
269 |
assoc[i]=string |
270 |
assoc[i+1]=string+1 |
271 |
assoc[i]=string |
272 |
assoc[i+1]=string+1 |
273 |
## END |
274 |
|
275 |
#### Array stored in associative array gets converted to string (without strict-array) |
276 |
|
277 |
array=('1 2' 3) |
278 |
declare -A d |
279 |
d['key']="${array[@]}" |
280 |
argv.py "${d['key']}" |
281 |
## stdout: ['1 2 3'] |
282 |
|
283 |
#### Indexed array as key of associative array coerces to string (without shopt -s strict-array) |
284 |
|
285 |
declare -a array=(1 2 3) |
286 |
declare -A assoc |
287 |
assoc[42]=43 |
288 |
assoc["${array[@]}"]=foo |
289 |
|
290 |
echo "${assoc["${array[@]}"]}" |
291 |
for entry in "${!assoc[@]}"; do |
292 |
echo $entry |
293 |
done | sort |
294 |
|
295 |
## STDOUT: |
296 |
foo |
297 |
1 2 3 |
298 |
42 |
299 |
## END |
300 |
|
301 |
#### Append to associative array value A['x']+='suffix' |
302 |
declare -A A |
303 |
A['x']='foo' |
304 |
A['x']+='bar' |
305 |
A['x']+='bar' |
306 |
argv.py "${A["x"]}" |
307 |
## STDOUT: |
308 |
['foobarbar'] |
309 |
## END |
310 |
|
311 |
#### Slice of associative array doesn't make sense in bash |
312 |
declare -A a |
313 |
a[xx]=1 |
314 |
a[yy]=2 |
315 |
a[zz]=3 |
316 |
a[aa]=4 |
317 |
a[bb]=5 |
318 |
#argv.py ${a["xx"]} |
319 |
argv.py ${a[@]: 0: 3} |
320 |
argv.py ${a[@]: 1: 3} |
321 |
argv.py ${a[@]: 2: 3} |
322 |
argv.py ${a[@]: 3: 3} |
323 |
argv.py ${a[@]: 4: 3} |
324 |
argv.py ${a[@]: 5: 3} |
325 |
## stdout-json: "" |
326 |
## status: 1 |
327 |
## BUG bash STDOUT: |
328 |
['2', '1', '5'] |
329 |
['2', '1', '5'] |
330 |
['1', '5', '4'] |
331 |
['5', '4', '3'] |
332 |
['4', '3'] |
333 |
['3'] |
334 |
## END |
335 |
## BUG bash status: 0 |
336 |
|
337 |
#### bash variable can have an associative array part and a string part |
338 |
|
339 |
# and $assoc is equivalent to ${assoc[0]}, just like regular arrays |
340 |
declare -A assoc |
341 |
assoc[1]=1 |
342 |
assoc[2]=2 |
343 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
344 |
assoc[0]=zero |
345 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
346 |
assoc=string |
347 |
echo ${assoc[1]} ${assoc[2]} ${assoc} |
348 |
## STDOUT: |
349 |
1 2 |
350 |
1 2 zero |
351 |
1 2 string |
352 |
## END |
353 |
## N-I osh stdout-json: "" |
354 |
## N-I osh status: 1 |
355 |
|
356 |
#### Associative array expressions inside (( )) with keys that look like numbers |
357 |
declare -A assoc |
358 |
assoc[0]=42 |
359 |
(( var = ${assoc[0]} )) |
360 |
echo $var |
361 |
(( var = assoc[0] )) |
362 |
echo $var |
363 |
## STDOUT: |
364 |
42 |
365 |
42 |
366 |
## END |
367 |
## N-I osh status: 1 |
368 |
## N-I osh STDOUT: |
369 |
42 |
370 |
## END |
371 |
|
372 |
#### (( A[5] += 42 )) |
373 |
declare -A A |
374 |
(( A[5] = 10 )) |
375 |
(( A[5] += 6 )) |
376 |
echo ${A[5]} |
377 |
## STDOUT: |
378 |
16 |
379 |
## END |
380 |
|
381 |
#### (( A[5] += 42 )) with empty cell |
382 |
shopt -u strict-arith # default zero cell |
383 |
declare -A A |
384 |
(( A[5] += 6 )) |
385 |
echo ${A[5]} |
386 |
## STDOUT: |
387 |
6 |
388 |
## END |
389 |
|
390 |
#### setting key to itself (from bash-bug mailing list) |
391 |
declare -A foo |
392 |
foo=(["key"]="value1") |
393 |
echo ${foo["key"]} |
394 |
foo=(["key"]="${foo["key"]} value2") |
395 |
echo ${foo["key"]} |
396 |
## STDOUT: |
397 |
value1 |
398 |
value1 value2 |
399 |
## END |
400 |
## BUG bash STDOUT: |
401 |
value1 |
402 |
value2 |
403 |
## END |
404 |
|
405 |
#### readonly associative array can't be modified |
406 |
declare -Ar A |
407 |
A['x']=1 |
408 |
echo status=$? |
409 |
## OK osh status: 1 |
410 |
## OK osh stdout-json: "" |
411 |
## STDOUT: |
412 |
status=1 |
413 |
## END |