1 | ## compare_shells: bash-4.4
|
2 | ## oils_failures_allowed: 4
|
3 |
|
4 |
|
5 | # NOTE:
|
6 | # -declare -A is required.
|
7 | #
|
8 | # Simply doing:
|
9 | # a=([aa]=b [foo]=bar ['a+1']=c)
|
10 | # gets utterly bizarre behavior.
|
11 | #
|
12 | # Associtative Arrays are COMPLETELY bash-specific. mksh doesn't even come
|
13 | # close. So I will probably not implement them, or implement something
|
14 | # slightly different, because the semantics are just weird.
|
15 |
|
16 | # http://www.gnu.org/software/bash/manual/html_node/Arrays.html
|
17 | # TODO: Need a SETUP section.
|
18 |
|
19 | #### Literal syntax ([x]=y)
|
20 | declare -A a
|
21 | a=([aa]=b [foo]=bar ['a+1']=c)
|
22 | echo ${a["aa"]}
|
23 | echo ${a["foo"]}
|
24 | echo ${a["a+1"]}
|
25 | ## STDOUT:
|
26 | b
|
27 | bar
|
28 | c
|
29 | ## END
|
30 |
|
31 | #### set associative array to indexed array literal (very surprising bash behavior)
|
32 | declare -A assoc=([k1]=foo [k2]='spam eggs')
|
33 | for v in "${assoc[@]}"; do echo $v; done | sort
|
34 | for v in "${!assoc[@]}"; do echo $v; done | sort
|
35 |
|
36 | # disallow this in OSH? Changing type?
|
37 |
|
38 | assoc=(foo 'spam eggs')
|
39 | argv.py "${assoc[@]}"
|
40 | argv.py "${!assoc[@]}"
|
41 |
|
42 | ## STDOUT:
|
43 | foo
|
44 | spam eggs
|
45 | k1
|
46 | k2
|
47 | ['foo', 'spam eggs']
|
48 | ['0', '1']
|
49 | ## END
|
50 | ## BUG bash STDOUT:
|
51 | foo
|
52 | spam eggs
|
53 | k1
|
54 | k2
|
55 | []
|
56 | []
|
57 | ## END
|
58 |
|
59 | #### Can't initialize assoc array with indexed array
|
60 | declare -A A=(1 2 3)
|
61 | echo status=$?
|
62 | ## STDOUT:
|
63 | status=2
|
64 | ## END
|
65 |
|
66 | # bash prints warnings to stderr but gives no indication of the problem
|
67 | ## BUG bash STDOUT:
|
68 | status=0
|
69 | ## END
|
70 |
|
71 |
|
72 | #### Initializing indexed array with assoc array
|
73 | declare -a a=([xx]=1 [yy]=2 [zz]=3)
|
74 | echo status=$?
|
75 | argv.py "${a[@]}"
|
76 | ## STDOUT:
|
77 | status=2
|
78 | []
|
79 | ## END
|
80 | ## BUG bash STDOUT:
|
81 | status=0
|
82 | ['3']
|
83 | ## END
|
84 |
|
85 | #### create empty assoc array, put, then get
|
86 | declare -A A # still undefined
|
87 | argv.py "${A[@]}"
|
88 | argv.py "${!A[@]}"
|
89 | A['foo']=bar
|
90 | echo ${A['foo']}
|
91 | ## STDOUT:
|
92 | []
|
93 | []
|
94 | bar
|
95 | ## END
|
96 |
|
97 | #### Empty value (doesn't use EmptyWord?)
|
98 | declare -A A=(["k"]= )
|
99 | argv.py "${A["k"]}"
|
100 | ## STDOUT:
|
101 | ['']
|
102 | ## END
|
103 |
|
104 | #### retrieve keys with !
|
105 | declare -A a
|
106 | var='x'
|
107 | a["$var"]=b
|
108 | a['foo']=bar
|
109 | a['a+1']=c
|
110 | for key in "${!a[@]}"; do
|
111 | echo $key
|
112 | done | sort
|
113 | ## STDOUT:
|
114 | a+1
|
115 | foo
|
116 | x
|
117 | ## END
|
118 |
|
119 | #### retrieve values with ${A[@]}
|
120 | declare -A A
|
121 | var='x'
|
122 | A["$var"]=b
|
123 | A['foo']=bar
|
124 | A['a+1']=c
|
125 | for val in "${A[@]}"; do
|
126 | echo $val
|
127 | done | sort
|
128 | ## STDOUT:
|
129 | b
|
130 | bar
|
131 | c
|
132 | ## END
|
133 |
|
134 | #### coerce to string with ${A[*]}, etc.
|
135 | declare -A A
|
136 | A['X X']=xx
|
137 | A['Y Y']=yy
|
138 | argv.py "${A[*]}"
|
139 | argv.py "${!A[*]}"
|
140 |
|
141 | argv.py ${A[@]}
|
142 | argv.py ${!A[@]}
|
143 | ## STDOUT:
|
144 | ['xx yy']
|
145 | ['X X Y Y']
|
146 | ['xx', 'yy']
|
147 | ['X', 'X', 'Y', 'Y']
|
148 | ## END
|
149 |
|
150 | #### ${A[@]/b/B}
|
151 | # but ${!A[@]/b/B} doesn't work
|
152 | declare -A A
|
153 | A['aa']=bbb
|
154 | A['bb']=ccc
|
155 | A['cc']=ddd
|
156 | for val in "${A[@]//b/B}"; do
|
157 | echo $val
|
158 | done | sort
|
159 | ## STDOUT:
|
160 | BBB
|
161 | ccc
|
162 | ddd
|
163 | ## END
|
164 |
|
165 | #### ${A[@]#prefix}
|
166 | declare -A A
|
167 | A['aa']=one
|
168 | A['bb']=two
|
169 | A['cc']=three
|
170 | for val in "${A[@]#t}"; do
|
171 | echo $val
|
172 | done | sort
|
173 | ## STDOUT:
|
174 | hree
|
175 | one
|
176 | wo
|
177 | ## END
|
178 |
|
179 | #### ${assoc} is like ${assoc[0]}
|
180 | declare -A a
|
181 |
|
182 | a=([aa]=b [foo]=bar ['a+1']=c)
|
183 | echo a="${a}"
|
184 |
|
185 | a=([0]=zzz)
|
186 | echo a="${a}"
|
187 |
|
188 | a=(['0']=yyy)
|
189 | echo a="${a}"
|
190 |
|
191 | ## STDOUT:
|
192 | a=
|
193 | a=zzz
|
194 | a=yyy
|
195 | ## END
|
196 |
|
197 | #### length ${#a[@]}
|
198 | declare -A a
|
199 | a["x"]=1
|
200 | a["y"]=2
|
201 | a["z"]=3
|
202 | echo "${#a[@]}"
|
203 | ## stdout: 3
|
204 |
|
205 | #### lookup with ${a[0]} -- "0" is a string
|
206 | declare -A a
|
207 | a["0"]=a
|
208 | a["1"]=b
|
209 | a["2"]=c
|
210 | echo 0 "${a[0]}" 1 "${a[1]}" 2 "${a[2]}"
|
211 | ## STDOUT:
|
212 | 0 a 1 b 2 c
|
213 | ## END
|
214 |
|
215 | #### lookup with double quoted strings "mykey"
|
216 | declare -A a
|
217 | a["aa"]=b
|
218 | a["foo"]=bar
|
219 | a['a+1']=c
|
220 | echo "${a["aa"]}" "${a["foo"]}" "${a["a+1"]}"
|
221 | ## STDOUT:
|
222 | b bar c
|
223 | ## END
|
224 |
|
225 | #### lookup with single quoted string
|
226 | declare -A a
|
227 | a["aa"]=b
|
228 | a["foo"]=bar
|
229 | a['a+1']=c
|
230 | echo "${a['a+1']}"
|
231 | ## stdout: c
|
232 |
|
233 | #### lookup with unquoted $key and quoted "$i$i"
|
234 | declare -A A
|
235 | A["aa"]=b
|
236 | A["foo"]=bar
|
237 |
|
238 | key=foo
|
239 | echo ${A[$key]}
|
240 | i=a
|
241 | echo ${A["$i$i"]} # note: ${A[$i$i]} doesn't work in OSH
|
242 | ## STDOUT:
|
243 | bar
|
244 | b
|
245 | ## END
|
246 |
|
247 | #### lookup by unquoted string doesn't work in OSH because it's a variable
|
248 | declare -A a
|
249 | a["aa"]=b
|
250 | a["foo"]=bar
|
251 | a['a+1']=c
|
252 | echo "${a[a+1]}"
|
253 | ## stdout-json: ""
|
254 | ## status: 1
|
255 | ## BUG bash stdout: c
|
256 | ## BUG bash status: 0
|
257 |
|
258 | #### bash bug: "i+1" and i+1 are the same key
|
259 |
|
260 | i=1
|
261 | array=(5 6 7)
|
262 | echo array[i]="${array[i]}"
|
263 | echo array[i+1]="${array[i+1]}"
|
264 |
|
265 | # arithmetic does NOT work here in bash. These are unquoted strings!
|
266 | declare -A assoc
|
267 | assoc[i]=$i
|
268 | assoc[i+1]=$i+1
|
269 |
|
270 | assoc["i"]=string
|
271 | assoc["i+1"]=string+1
|
272 |
|
273 | echo assoc[i]="${assoc[i]}"
|
274 | echo assoc[i+1]="${assoc[i+1]}"
|
275 |
|
276 | echo assoc[i]="${assoc["i"]}"
|
277 | echo assoc[i+1]="${assoc["i+1"]}"
|
278 |
|
279 | ## status: 1
|
280 | ## STDOUT:
|
281 | array[i]=6
|
282 | array[i+1]=7
|
283 | ## END
|
284 | ## BUG bash status: 0
|
285 | ## BUG bash STDOUT:
|
286 | array[i]=6
|
287 | array[i+1]=7
|
288 | assoc[i]=string
|
289 | assoc[i+1]=string+1
|
290 | assoc[i]=string
|
291 | assoc[i+1]=string+1
|
292 | ## END
|
293 |
|
294 | #### Array stored in associative array gets converted to string (without strict_array)
|
295 |
|
296 | array=('1 2' 3)
|
297 | declare -A d
|
298 | d['key']="${array[@]}"
|
299 | argv.py "${d['key']}"
|
300 | ## stdout: ['1 2 3']
|
301 |
|
302 | #### Indexed array as key of associative array coerces to string (without shopt -s strict_array)
|
303 |
|
304 | declare -a array=(1 2 3)
|
305 | declare -A assoc
|
306 | assoc[42]=43
|
307 | assoc["${array[@]}"]=foo
|
308 |
|
309 | echo "${assoc["${array[@]}"]}"
|
310 | for entry in "${!assoc[@]}"; do
|
311 | echo $entry
|
312 | done | sort
|
313 |
|
314 | ## STDOUT:
|
315 | foo
|
316 | 1 2 3
|
317 | 42
|
318 | ## END
|
319 |
|
320 | #### Append to associative array value A['x']+='suffix'
|
321 | declare -A A
|
322 | A['x']='foo'
|
323 | A['x']+='bar'
|
324 | A['x']+='bar'
|
325 | argv.py "${A["x"]}"
|
326 | ## STDOUT:
|
327 | ['foobarbar']
|
328 | ## END
|
329 |
|
330 | #### Slice of associative array doesn't make sense in bash
|
331 | declare -A a
|
332 | a[xx]=1
|
333 | a[yy]=2
|
334 | a[zz]=3
|
335 | a[aa]=4
|
336 | a[bb]=5
|
337 | #argv.py ${a["xx"]}
|
338 | argv.py ${a[@]: 0: 3}
|
339 | argv.py ${a[@]: 1: 3}
|
340 | argv.py ${a[@]: 2: 3}
|
341 | argv.py ${a[@]: 3: 3}
|
342 | argv.py ${a[@]: 4: 3}
|
343 | argv.py ${a[@]: 5: 3}
|
344 | ## stdout-json: ""
|
345 | ## status: 1
|
346 | ## BUG bash STDOUT:
|
347 | ['2', '1', '5']
|
348 | ['2', '1', '5']
|
349 | ['1', '5', '4']
|
350 | ['5', '4', '3']
|
351 | ['4', '3']
|
352 | ['3']
|
353 | ## END
|
354 | ## BUG bash status: 0
|
355 |
|
356 | #### bash variable can have an associative array part and a string part
|
357 |
|
358 | # and $assoc is equivalent to ${assoc[0]}, just like regular arrays
|
359 | declare -A assoc
|
360 | assoc[1]=1
|
361 | assoc[2]=2
|
362 | echo ${assoc[1]} ${assoc[2]} ${assoc}
|
363 | assoc[0]=zero
|
364 | echo ${assoc[1]} ${assoc[2]} ${assoc}
|
365 | assoc=string
|
366 | echo ${assoc[1]} ${assoc[2]} ${assoc}
|
367 | ## STDOUT:
|
368 | 1 2
|
369 | 1 2 zero
|
370 | 1 2 string
|
371 | ## END
|
372 | ## N-I osh status: 1
|
373 | ## N-I osh STDOUT:
|
374 | 1 2
|
375 | 1 2 zero
|
376 | ## END
|
377 |
|
378 | #### Associative array expressions inside (( )) with keys that look like numbers
|
379 | declare -A assoc
|
380 | assoc[0]=42
|
381 | (( var = ${assoc[0]} ))
|
382 | echo $var
|
383 | (( var = assoc[0] ))
|
384 | echo $var
|
385 | ## STDOUT:
|
386 | 42
|
387 | 42
|
388 | ## END
|
389 |
|
390 | #### (( A[5] += 42 ))
|
391 | declare -A A
|
392 | (( A[5] = 10 ))
|
393 | (( A[5] += 6 ))
|
394 | echo ${A[5]}
|
395 | ## STDOUT:
|
396 | 16
|
397 | ## END
|
398 |
|
399 | #### (( A[5] += 42 )) with empty cell
|
400 | shopt -u strict_arith # default zero cell
|
401 | declare -A A
|
402 | (( A[5] += 6 ))
|
403 | echo ${A[5]}
|
404 | ## STDOUT:
|
405 | 6
|
406 | ## END
|
407 |
|
408 | #### setting key to itself (from bash-bug mailing list)
|
409 | declare -A foo
|
410 | foo=(["key"]="value1")
|
411 | echo ${foo["key"]}
|
412 | foo=(["key"]="${foo["key"]} value2")
|
413 | echo ${foo["key"]}
|
414 | ## STDOUT:
|
415 | value1
|
416 | value1 value2
|
417 | ## END
|
418 | ## BUG bash STDOUT:
|
419 | value1
|
420 | value2
|
421 | ## END
|
422 |
|
423 | #### readonly associative array can't be modified
|
424 | declare -Ar A
|
425 | A['x']=1
|
426 | echo status=$?
|
427 | ## OK osh status: 1
|
428 | ## OK osh stdout-json: ""
|
429 | ## STDOUT:
|
430 | status=1
|
431 | ## END
|
432 |
|
433 | #### associative array and brace expansion
|
434 | declare -A A=([k1]=v [k2]=-{a,b}-)
|
435 | echo ${A["k1"]}
|
436 | echo ${A["k2"]}
|
437 | ## STDOUT:
|
438 | v
|
439 | -{a,b}-
|
440 | ## END
|
441 |
|
442 | #### bash mangles array #1
|
443 | a=([k1]=v1 [k2]=v2)
|
444 | echo ${a["k1"]}
|
445 | echo ${a["k2"]}
|
446 | ## STDOUT:
|
447 | v1
|
448 | v2
|
449 | ## END
|
450 | ## BUG bash STDOUT:
|
451 | v2
|
452 | v2
|
453 | ## END
|
454 |
|
455 | #### bash mangles array and brace #2
|
456 | a=([k2]=-{a,b}-)
|
457 | echo ${a["k2"]}
|
458 | ## STDOUT:
|
459 | -{a,b}-
|
460 | ## END
|
461 | ## BUG bash STDOUT:
|
462 | [k2]=-a-
|
463 | ## END
|
464 |
|
465 | #### declare -A A=() allowed
|
466 | set -o nounset
|
467 | shopt -s strict_arith || true
|
468 |
|
469 | declare -A ASSOC=()
|
470 | echo len=${#ASSOC[@]}
|
471 |
|
472 | # Check that it really can be used like an associative array
|
473 | ASSOC['k']='32'
|
474 | echo len=${#ASSOC[@]}
|
475 |
|
476 | # bash allows a variable to be an associative array AND unset, while OSH
|
477 | # doesn't
|
478 | set +o nounset
|
479 | declare -A u
|
480 | echo unset len=${#u[@]}
|
481 | ## STDOUT:
|
482 | len=0
|
483 | len=1
|
484 | unset len=0
|
485 | ## END
|
486 |
|
487 | #### unset -v and assoc array
|
488 | shopt -s eval_unsafe_arith || true
|
489 |
|
490 | show-len() {
|
491 | echo len=${#assoc[@]}
|
492 | }
|
493 |
|
494 | declare -A assoc=(['K']=val)
|
495 | show-len
|
496 |
|
497 | unset -v 'assoc["K"]'
|
498 | show-len
|
499 |
|
500 | declare -A assoc=(['K']=val)
|
501 | show-len
|
502 | key=K
|
503 | unset -v 'assoc[$key]'
|
504 | show-len
|
505 |
|
506 | declare -A assoc=(['K']=val)
|
507 | show-len
|
508 | unset -v 'assoc[$(echo K)]'
|
509 | show-len
|
510 |
|
511 | # ${prefix} doesn't work here, even though it does in arithmetic
|
512 | #declare -A assoc=(['K']=val)
|
513 | #show-len
|
514 | #prefix=as
|
515 | #unset -v '${prefix}soc[$key]'
|
516 | #show-len
|
517 |
|
518 | ## STDOUT:
|
519 | len=1
|
520 | len=0
|
521 | len=1
|
522 | len=0
|
523 | len=1
|
524 | len=0
|
525 | ## END
|
526 |
|
527 | #### nameref and assoc array
|
528 | show-values() {
|
529 | echo values: ${A[@]}
|
530 | }
|
531 |
|
532 | declare -A A=(['K']=val)
|
533 | show-values
|
534 |
|
535 | declare -n ref='A["K"]'
|
536 | echo before $ref
|
537 | ref='val2'
|
538 | echo after $ref
|
539 | show-values
|
540 |
|
541 | echo ---
|
542 |
|
543 | key=K
|
544 | declare -n ref='A[$key]'
|
545 | echo before $ref
|
546 | ref='val3'
|
547 | echo after $ref
|
548 | show-values
|
549 |
|
550 | ## STDOUT:
|
551 | values: val
|
552 | before val
|
553 | after val2
|
554 | values: val2
|
555 | ---
|
556 | before val2
|
557 | after val3
|
558 | values: val3
|
559 | ## END
|
560 |
|
561 | #### ${!ref} and assoc array
|
562 |
|
563 | show-values() {
|
564 | echo values: ${A[@]}
|
565 | }
|
566 |
|
567 | declare -A A=(['K']=val)
|
568 | show-values
|
569 |
|
570 | declare ref='A["K"]'
|
571 | echo ref ${!ref}
|
572 |
|
573 | key=K
|
574 | declare ref='A[$key]'
|
575 | echo ref ${!ref}
|
576 |
|
577 | ## STDOUT:
|
578 | values: val
|
579 | ref val
|
580 | ref val
|
581 | ## END
|
582 |
|
583 | #### printf -v and assoc array
|
584 |
|
585 | show-values() {
|
586 | echo values: ${assoc[@]}
|
587 | }
|
588 |
|
589 | declare -A assoc=(['K']=val)
|
590 | show-values
|
591 |
|
592 | printf -v 'assoc["K"]' '/%s/' val2
|
593 | show-values
|
594 |
|
595 | key=K
|
596 | printf -v 'assoc[$key]' '/%s/' val3
|
597 | show-values
|
598 |
|
599 | # Somehow bash doesn't allow this
|
600 | #prefix=as
|
601 | #printf -v '${prefix}soc[$key]' '/%s/' val4
|
602 | #show-values
|
603 |
|
604 | ## STDOUT:
|
605 | values: val
|
606 | values: /val2/
|
607 | values: /val3/
|
608 | ## END
|
609 |
|
610 | #### bash bug: (( A["$key"] = 1 )) doesn't work
|
611 | key='\'
|
612 | declare -A A
|
613 | #A["$key"]=1
|
614 |
|
615 | # Works in both
|
616 | #A["$key"]=42
|
617 |
|
618 | # Works in bash only
|
619 | #(( A[\$key] = 42 ))
|
620 |
|
621 | (( A["$key"] = 42 ))
|
622 |
|
623 | argv.py "${!A[@]}"
|
624 | argv.py "${A[@]}"
|
625 | ## STDOUT:
|
626 | ['\\']
|
627 | ['42']
|
628 | ## END
|
629 | ## BUG bash STDOUT:
|
630 | []
|
631 | []
|
632 | ## END
|
633 |
|
634 |
|
635 | #### Implicit increment of keys
|
636 | declare -a arr=( [30]=a b [40]=x y)
|
637 | argv.py "${!arr[@]}"
|
638 | argv.py "${arr[@]}"
|
639 |
|
640 | # osh says "expected associative array pair"
|
641 |
|
642 | ## STDOUT:
|
643 | ['30', '31', '40', '41']
|
644 | ['a', 'b', 'x', 'y']
|
645 | ## END
|
646 |
|
647 |
|
648 | #### [[ -v assoc[key] ]]
|
649 |
|
650 | typeset -A assoc
|
651 | assoc=([empty]='' [k]=v)
|
652 |
|
653 | [[ -v assoc[empty] ]]
|
654 | echo empty=$?
|
655 |
|
656 | [[ -v assoc[k] ]]
|
657 | echo k=$?
|
658 |
|
659 | [[ -v assoc[nonexistent] ]]
|
660 | echo nonexistent=$?
|
661 |
|
662 | echo ---
|
663 | # Now with quotes
|
664 |
|
665 | [[ -v assoc["empty"] ]]
|
666 | echo empty=$?
|
667 |
|
668 | [[ -v assoc['k'] ]]
|
669 | echo k=$?
|
670 |
|
671 | [[ -v assoc['nonexistent'] ]]
|
672 | echo nonexistent=$?
|
673 |
|
674 | echo ---
|
675 | # Now with var expansion
|
676 |
|
677 | key=empty
|
678 | [[ -v assoc[$key] ]]
|
679 | echo empty=$?
|
680 |
|
681 | key=k
|
682 | [[ -v assoc[$key] ]]
|
683 | echo k=$?
|
684 |
|
685 | key=nonexistent
|
686 | [[ -v assoc[$key] ]]
|
687 | echo nonexistent=$?
|
688 |
|
689 | ## STDOUT:
|
690 | empty=0
|
691 | k=0
|
692 | nonexistent=1
|
693 | ---
|
694 | empty=0
|
695 | k=0
|
696 | nonexistent=1
|
697 | ---
|
698 | empty=0
|
699 | k=0
|
700 | nonexistent=1
|
701 | ## END
|
702 |
|
703 | ## N-I mksh status: 1
|
704 | ## N-I mksh STDOUT:
|
705 | ## END
|