OILS / spec / array.test.sh View on Github | oilshell.org

650 lines, 302 significant
1
2# TODO: Need a SETUP section.
3
4#### SETUP
5a=(1 '2 3')
6
7#### "${a[@]}" and "${a[*]}"
8a=(1 '2 3')
9argv.py "${a[@]}" "${a[*]}"
10## stdout: ['1', '2 3', '1 2 3']
11
12#### ${a[@]} and ${a[*]}
13a=(1 '2 3')
14argv.py ${a[@]} ${a[*]}
15## stdout: ['1', '2', '3', '1', '2', '3']
16
17#### 4 ways to interpolate empty array
18argv.py 1 "${a[@]}" 2 ${a[@]} 3 "${a[*]}" 4 ${a[*]} 5
19## stdout: ['1', '2', '3', '', '4', '5']
20
21#### empty array
22empty=()
23argv.py "${empty[@]}"
24## stdout: []
25
26#### Empty array with :-
27empty=()
28argv.py ${empty[@]:-not one} "${empty[@]:-not one}"
29## stdout: ['not', 'one', 'not one']
30
31#### nounset / set -u with empty array (bug in bash 4.3, fixed in 4.4)
32
33# http://lists.gnu.org/archive/html/help-bash/2017-09/msg00005.html
34
35set -o nounset
36empty=()
37argv.py "${empty[@]}"
38echo status=$?
39## STDOUT:
40[]
41status=0
42## END
43## BUG mksh stdout-json: ""
44## BUG mksh status: 1
45
46#### local array
47# mksh support local variables, but not local arrays, oddly.
48f() {
49 local a=(1 '2 3')
50 argv.py "${a[0]}"
51}
52f
53## stdout: ['1']
54## status: 0
55## BUG mksh status: 1
56## BUG mksh stdout-json: ""
57
58#### Command with with word splitting in array
59array=('1 2' $(echo '3 4'))
60argv.py "${array[@]}"
61## stdout: ['1 2', '3', '4']
62
63#### space before ( in array initialization
64# NOTE: mksh accepts this, but bash doesn't
65a= (1 '2 3')
66echo $a
67## status: 2
68## OK mksh status: 0
69## OK mksh stdout: 1
70
71#### array over multiple lines
72a=(
731
74'2 3'
75)
76argv.py "${a[@]}"
77## stdout: ['1', '2 3']
78## status: 0
79
80#### array with invalid token
81a=(
821
83&
84'2 3'
85)
86argv.py "${a[@]}"
87## status: 2
88## OK mksh status: 1
89
90#### array with empty string
91empty=('')
92argv.py "${empty[@]}"
93## stdout: ['']
94
95#### Retrieve index
96a=(1 '2 3')
97argv.py "${a[1]}"
98## stdout: ['2 3']
99
100#### Retrieve out of bounds index
101a=(1 '2 3')
102argv.py "${a[3]}"
103## stdout: ['']
104
105#### Negative index
106a=(1 '2 3')
107argv.py "${a[-1]}" "${a[-2]}" "${a[-5]}" # last one out of bounds
108## stdout: ['2 3', '1', '']
109## N-I mksh stdout: ['', '', '']
110
111#### Negative index and sparse array
112a=(0 1 2 3 4)
113unset a[1]
114unset a[4]
115echo "${a[@]}"
116echo -1 ${a[-1]}
117echo -2 ${a[-2]}
118echo -3 ${a[-3]}
119echo -4 ${a[-4]}
120echo -5 ${a[-5]}
121
122a[-1]+=0 # append 0 on the end
123echo ${a[@]}
124(( a[-1] += 42 ))
125echo ${a[@]}
126
127## STDOUT:
1280 2 3
129-1 3
130-2 2
131-3
132-4 0
133-5
1340 2 30
1350 2 72
136## END
137## BUG mksh STDOUT:
1380 2 3
139-1
140-2
141-3
142-4
143-5
1440 2 3 0
1450 2 3 42
146## END
147
148#### Negative index and sparse array
149a=(0 1)
150unset 'a[-1]' # remove last element
151a+=(2 3)
152echo ${a[0]} $((a[0]))
153echo ${a[1]} $((a[1]))
154echo ${a[2]} $((a[2]))
155echo ${a[3]} $((a[3]))
156## STDOUT:
1570 0
1582 2
1593 3
1600
161## END
162## BUG mksh STDOUT:
1630 0
1641 1
1652 2
1663 3
167## END
168
169#### Length after unset
170a=(0 1 2 3)
171unset a[-1]
172echo len=${#a[@]}
173unset a[-1]
174echo len=${#a[@]}
175## STDOUT:
176len=3
177len=2
178## END
179## BUG mksh STDOUT:
180len=4
181len=4
182## END
183
184#### Retrieve index that is a variable
185a=(1 '2 3')
186i=1
187argv.py "${a[$i]}"
188## stdout: ['2 3']
189
190#### Retrieve index that is a variable without $
191a=(1 '2 3')
192i=5
193argv.py "${a[i-4]}"
194## stdout: ['2 3']
195
196#### Retrieve index that is a command sub
197a=(1 '2 3')
198argv.py "${a[$(echo 1)]}"
199## stdout: ['2 3']
200
201#### Retrieve array indices with ${!a}
202a=(1 '2 3')
203argv.py "${!a[@]}"
204## stdout: ['0', '1']
205
206#### Retrieve sparse array indices with ${!a}
207a=()
208(( a[99]=1 ))
209argv.py "${!a[@]}"
210## STDOUT:
211['99']
212## END
213
214#### ${!a[1]} is named ref in bash
215# mksh ignores it
216foo=bar
217a=('1 2' foo '2 3')
218argv.py "${!a[1]}"
219## status: 0
220## stdout: ['bar']
221## N-I mksh stdout: ['a[1]']
222
223#### ${!a} on array
224
225# bash gives empty string because it's like a[0]
226# mksh gives the name of the variable with !. Very weird.
227
228a=(1 '2 3')
229argv.py "${!a}"
230
231## stdout: ['']
232## status: 0
233## BUG mksh stdout: ['a']
234## BUG mksh status: 0
235
236#### All elements unquoted
237a=(1 '2 3')
238argv.py ${a[@]}
239## stdout: ['1', '2', '3']
240
241#### All elements quoted
242a=(1 '2 3')
243argv.py "${a[@]}"
244## stdout: ['1', '2 3']
245
246#### $*
247a=(1 '2 3')
248argv.py ${a[*]}
249## stdout: ['1', '2', '3']
250
251#### "$*"
252a=(1 '2 3')
253argv.py "${a[*]}"
254## stdout: ['1 2 3']
255
256#### Interpolate array into array
257a=(1 '2 3')
258a=(0 "${a[@]}" '4 5')
259argv.py "${a[@]}"
260## stdout: ['0', '1', '2 3', '4 5']
261
262#### Exporting array doesn't do anything, not even first element
263# bash parses, but doesn't execute.
264# mksh gives syntax error -- parses differently with 'export'
265# osh no longer parses this statically.
266export PYTHONPATH=(a b c)
267export PYTHONPATH=a # NOTE: in bash, this doesn't work afterward!
268printenv.py PYTHONPATH
269## stdout-json: ""
270## status: 1
271## OK bash stdout: None
272## OK bash status: 0
273
274#### Arrays can't be used as env bindings
275# Hm bash it treats it as a string!
276A=a B=(b b) printenv.py A B
277## status: 2
278## stdout-json: ""
279## OK bash stdout-json: "a\n(b b)\n"
280## OK bash status: 0
281## OK mksh status: 1
282
283#### Set element
284a=(1 '2 3')
285a[0]=9
286argv.py "${a[@]}"
287## stdout: ['9', '2 3']
288
289#### Set element with var ref
290a=(1 '2 3')
291i=0
292a[$i]=9
293argv.py "${a[@]}"
294## stdout: ['9', '2 3']
295
296#### Set element with array ref
297# This makes parsing a little more complex. Anything can be inside [],
298# including other [].
299a=(1 '2 3')
300i=(0 1)
301a[${i[1]}]=9
302argv.py "${a[@]}"
303## stdout: ['1', '9']
304
305#### Set array item to array
306a=(1 2)
307a[0]=(3 4)
308echo "status=$?"
309## stdout-json: ""
310## status: 2
311## N-I mksh status: 1
312## BUG bash stdout: status=1
313## BUG bash status: 0
314
315#### Slice of array with [@]
316# mksh doesn't support this syntax! It's a bash extension.
317a=(1 2 3)
318argv.py "${a[@]:1:2}"
319## stdout: ['2', '3']
320## N-I mksh status: 1
321## N-I mksh stdout-json: ""
322
323#### Negative slice begin
324# mksh doesn't support this syntax! It's a bash extension.
325# NOTE: for some reason -2) has to be in parens? Ah that's because it
326# conflicts with :-! That's silly. You can also add a space.
327a=(1 2 3 4 5)
328argv.py "${a[@]:(-4)}"
329## stdout: ['2', '3', '4', '5']
330## N-I mksh status: 1
331## N-I mksh stdout-json: ""
332
333#### Negative slice length
334a=(1 2 3 4 5)
335argv.py "${a[@]: 1: -3}"
336## status: 1
337## stdout-json: ""
338
339#### Slice with arithmetic
340a=(1 2 3)
341i=5
342argv.py "${a[@]:i-4:2}"
343## stdout: ['2', '3']
344## N-I mksh status: 1
345## N-I mksh stdout-json: ""
346
347#### Number of elements
348a=(1 '2 3')
349echo "${#a[@]}" ${#a[@]} # bug fix: also test without quotes
350## stdout: 2 2
351
352#### Length of an element
353a=(1 '2 3')
354echo "${#a[1]}"
355## stdout: 3
356
357#### Iteration
358a=(1 '2 3')
359for v in "${a[@]}"; do
360 echo $v
361done
362## stdout-json: "1\n2 3\n"
363
364#### glob within array yields separate elements
365touch _tmp/y.Y _tmp/yy.Y
366a=(_tmp/*.Y)
367argv.py "${a[@]}"
368## stdout: ['_tmp/y.Y', '_tmp/yy.Y']
369
370#### declare array and then append
371declare -a array
372array+=(a)
373array+=(b c)
374argv.py "${array[@]}"
375## stdout: ['a', 'b', 'c']
376
377#### Array syntax in wrong place
378ls foo=(1 2)
379## status: 1
380## OK bash status: 2
381
382#### Single array with :-
383# bash does EMPTY ELISION here, unless it's double quoted. mksh has
384# more sane behavior. OSH is better.
385single=('')
386argv.py ${single[@]:-none} x "${single[@]:-none}"
387## OK osh stdout: ['x', '']
388## OK bash stdout: ['none', 'x', '']
389## OK mksh stdout: ['none', 'x', 'none']
390
391#### Stripping a whole array unquoted
392# Problem: it joins it first.
393files=('foo.c' 'sp ace.h' 'bar.c')
394argv.py ${files[@]%.c}
395## status: 0
396## stdout: ['foo', 'sp', 'ace.h', 'bar']
397## N-I mksh status: 1
398## N-I mksh stdout-json: ""
399
400#### Stripping a whole array quoted
401files=('foo.c' 'sp ace.h' 'bar.c')
402argv.py "${files[@]%.c}"
403## status: 0
404## stdout: ['foo', 'sp ace.h', 'bar']
405## N-I mksh status: 1
406## N-I mksh stdout-json: ""
407
408#### Multiple subscripts not allowed
409# NOTE: bash 4.3 had a bug where it ignored the bad subscript, but now it is
410# fixed.
411a=('123' '456')
412argv.py "${a[0]}" "${a[0][0]}"
413## stdout-json: ""
414## status: 2
415## OK bash/mksh status: 1
416
417#### Length op, index op, then transform op is not allowed
418a=('123' '456')
419echo "${#a[0]}" "${#a[0]/1/xxx}"
420## stdout-json: ""
421## status: 2
422## OK bash/mksh status: 1
423
424#### ${mystr[@]} and ${mystr[*]} are no-ops
425s='abc'
426echo ${s[@]}
427echo ${s[*]}
428## STDOUT:
429abc
430abc
431## END
432
433#### ${mystr[@]} and ${mystr[*]} disallowed with strict_array
434
435$SH -c 'shopt -s strict_array; s="abc"; echo ${s[@]}'
436echo status=$?
437
438$SH -c 'shopt -s strict_array; s="abc"; echo ${s[*]}'
439echo status=$?
440
441## status: 0
442## STDOUT:
443status=1
444status=1
445## END
446## N-I bash/mksh STDOUT:
447abc
448status=0
449abc
450status=0
451## END
452
453#### Create a "user" array out of the argv array
454set -- 'a b' 'c'
455array1=('x y' 'z')
456array2=("$@")
457argv.py "${array1[@]}" "${array2[@]}"
458## stdout: ['x y', 'z', 'a b', 'c']
459
460#### Tilde expansion within array
461HOME=/home/bob
462a=(~/src ~/git)
463echo "${a[@]}"
464## stdout: /home/bob/src /home/bob/git
465
466#### Brace Expansion within Array
467a=(-{a,b} {c,d}-)
468echo "${a[@]}"
469## stdout: -a -b c- d-
470
471#### array default
472default=('1 2' '3')
473argv.py "${undef[@]:-${default[@]}}"
474## stdout: ['1 2', '3']
475
476#### Singleton Array Copy and Assign. OSH can't index strings with ints
477a=( '12 3' )
478b=( "${a[@]}" )
479c="${a[@]}" # This decays it to a string
480d=${a[*]} # This decays it to a string
481echo ${#a[0]} ${#b[0]}
482echo ${#a[@]} ${#b[@]}
483
484# osh is intentionally stricter, and these fail.
485echo ${#c[0]} ${#d[0]}
486echo ${#c[@]} ${#d[@]}
487
488## status: 1
489## STDOUT:
4904 4
4911 1
492## END
493## OK bash/mksh status: 0
494## OK bash/mksh STDOUT:
4954 4
4961 1
4974 4
4981 1
499## END
500
501#### declare -a / local -a is empty array
502declare -a myarray
503argv.py "${myarray[@]}"
504myarray+=('x')
505argv.py "${myarray[@]}"
506
507f() {
508 local -a myarray
509 argv.py "${myarray[@]}"
510 myarray+=('x')
511 argv.py "${myarray[@]}"
512}
513f
514## STDOUT:
515[]
516['x']
517[]
518['x']
519## END
520
521#### Create sparse array
522a=()
523(( a[99]=1 )) # osh doesn't parse index assignment outside arithmetic yet
524echo len=${#a[@]}
525argv.py "${a[@]}"
526echo "unset=${a[33]}"
527echo len-of-unset=${#a[33]}
528## STDOUT:
529len=1
530['1']
531unset=
532len-of-unset=0
533## END
534
535#### Create sparse array implicitly
536(( a[99]=1 ))
537echo len=${#a[@]}
538argv.py "${a[@]}"
539echo "unset=${a[33]}"
540echo len-of-unset=${#a[33]}
541## STDOUT:
542len=1
543['1']
544unset=
545len-of-unset=0
546## END
547
548#### Append sparse arrays
549a=()
550(( a[99]=1 ))
551b=()
552(( b[33]=2 ))
553(( b[66]=3 ))
554a+=( "${b[@]}" )
555argv.py "${a[@]}"
556argv.py "${a[99]}" "${a[100]}" "${a[101]}"
557## STDOUT:
558['1', '2', '3']
559['1', '2', '3']
560## END
561
562#### Slice of sparse array with [@]
563# mksh doesn't support this syntax! It's a bash extension.
564(( a[33]=1 ))
565(( a[66]=2 ))
566(( a[99]=2 ))
567argv.py "${a[@]:15:2}"
568## stdout: ['1', '2']
569## N-I mksh status: 1
570## N-I mksh stdout-json: ""
571
572#### Using an array itself as the index on LHS
573shopt -u strict_arith
574a[a]=42
575a[a]=99
576argv.py "${a[@]}" "${a[0]}" "${a[42]}" "${a[99]}"
577
578## status: 0
579## STDOUT:
580['42', '99', '42', '99', '']
581## END
582
583#### Using an array itself as the index on RHS
584shopt -u strict_arith
585a=(1 2 3)
586(( x = a[a] ))
587echo $x
588## status: 0
589## STDOUT:
5902
591## END
592
593#### a[$x$y] on LHS and RHS
594x=1
595y=2
596a[$x$y]=foo
597
598# not allowed by OSH parsing
599#echo ${a[$x$y]}
600
601echo ${a[12]}
602echo ${#a[@]}
603
604## STDOUT:
605foo
6061
607## END
608
609
610#### Dynamic parsing of LHS a[$code]=value
611
612declare -a array
613array[x=1]='one'
614
615code='y=2'
616#code='1+2' # doesn't work either
617array[$code]='two'
618
619argv.py "${array[@]}"
620echo x=$x
621echo y=$y
622
623## STDOUT:
624['one', 'two']
625x=1
626y=2
627## END
628## N-I dash stdout-json: ""
629## N-I dash status: 2
630
631#### Dynamic parsing of RHS ${a[$code]}
632declare -a array
633array=(zero one two three)
634
635echo ${array[1+2]}
636
637code='1+2'
638echo ${array[$code]}
639
640## STDOUT:
641three
642three
643## END
644
645# it still dynamically parses
646
647## OK zsh STDOUT:
648two
649two
650## END