501 lines
12 KiB
YAML
501 lines
12 KiB
YAML
name: "Arrays"
|
|
incompatible_configs: ["sh"]
|
|
common_test_files:
|
|
- path: "helpers.sh"
|
|
contents: |
|
|
stable_print_assoc_array() {
|
|
# TODO(nameref): enable use of nameref when implemented; for now
|
|
# we assume the name of the array is assoc_array
|
|
# local -n assoc_array=$1
|
|
local key
|
|
|
|
for key in $(printf "%s\n" "${!assoc_array[@]}" | sort -n); do
|
|
echo "\"${key}\" => ${assoc_array[${key}]}"
|
|
done
|
|
}
|
|
cases:
|
|
- name: "Basic indexed array definition and access"
|
|
stdin: |
|
|
var=(a b c)
|
|
echo "var: $var"
|
|
echo "var: ${var}"
|
|
echo "var[0]: ${var[0]}"
|
|
echo "var[1]: ${var[1]}"
|
|
echo "var[2]: ${var[2]}"
|
|
echo "var[3]: ${var[3]}"
|
|
echo "var[4]: ${var[4]}"
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Negative indexed array access"
|
|
stdin: |
|
|
var=(a b c)
|
|
echo "var[-1]: ${var[-1]}"
|
|
echo "var[-2]: ${var[-2]}"
|
|
echo "var[-3]: ${var[-3]}"
|
|
|
|
- name: "Too large negative indexed array access"
|
|
ignore_stderr: true
|
|
stdin: |
|
|
var=(a b c)
|
|
echo "var[-4]: ${var[-4]}"
|
|
|
|
- name: "Negative indexed array access (set)"
|
|
stdin: |
|
|
var=(a b c d e f g)
|
|
var[-1]=x
|
|
var[-3]=z
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Too large negative indexed array access (set)"
|
|
ignore_stderr: true
|
|
stdin: |
|
|
var=(a b c)
|
|
var[-4]=x
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Define array with expansion"
|
|
stdin: |
|
|
body='a b'
|
|
|
|
var=($body)
|
|
declare -p var
|
|
|
|
declare -a var2=($body)
|
|
declare -p var2
|
|
|
|
- name: "Arrays with empty values"
|
|
stdin: |
|
|
var1=(a "" c)
|
|
declare -p var1
|
|
|
|
var2=(a "$nonexistent" c)
|
|
declare -p var2
|
|
|
|
var3=("" "" "")
|
|
declare -p var3
|
|
|
|
- name: "Basic associative array definition and access"
|
|
stdin: |
|
|
declare -A var=([0]=99 [a]=3 [b]=4 [c]=5)
|
|
echo "var: $var"
|
|
echo "var: ${var}"
|
|
echo "var[0]: ${var[0]}"
|
|
echo "var[a]: ${var[a]}"
|
|
echo "var[b]: ${var[b]}"
|
|
echo "var[c]: ${var[c]}"
|
|
echo "var[d]: ${var[d]}"
|
|
|
|
key="a"
|
|
echo "var[key]: ${var[${key}]}"
|
|
|
|
- name: "Array updating via index"
|
|
stdin: |
|
|
var=(a b c)
|
|
var[1]="d"
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Array index assignment"
|
|
stdin: |
|
|
x=(3 2 1)
|
|
y[${x[0]}]=10
|
|
y[x[1]]=11
|
|
declare -p y
|
|
|
|
- name: "Arithmetic index assignment on declared-but-unset variable"
|
|
stdin: |
|
|
declare a
|
|
i=1
|
|
a[i]=help
|
|
declare -p a
|
|
|
|
- name: "Arithmetic index assignment on local declared-but-unset variable"
|
|
stdin: |
|
|
f() {
|
|
local a
|
|
i=1
|
|
a[i]=help
|
|
declare -p a
|
|
}
|
|
f
|
|
|
|
- name: "Arithmetic index assignment on scalar variable"
|
|
stdin: |
|
|
a=foo
|
|
i=1
|
|
a[i]=help
|
|
declare -p a
|
|
|
|
- name: "Arithmetic index assignment on undeclared variable"
|
|
stdin: |
|
|
i=1
|
|
a[i]=help
|
|
declare -p a
|
|
|
|
- name: "Replacing array with string"
|
|
stdin: |
|
|
var=(a b c)
|
|
var="x"
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Array replacing"
|
|
stdin: |
|
|
var=(a b c)
|
|
var=(d e f)
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Appending array to indexed array"
|
|
stdin: |
|
|
var=(a b c)
|
|
var+=(e f g)
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
var+=("" "" "")
|
|
declare -p var
|
|
|
|
var+=(h "i" "$nonexistent" j)
|
|
var+=(j k l)
|
|
declare -p var
|
|
|
|
- name: "Appending array to declared-but-unset indexed array"
|
|
stdin: |
|
|
declare -a var
|
|
var+=(e f g)
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Appending item to indexed array"
|
|
stdin: |
|
|
var=(a b c)
|
|
var+=d
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Appending item to element of indexed array"
|
|
stdin: |
|
|
declare -a var=(1 2 3)
|
|
var[1]+=2
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Appending item to element of int indexed array"
|
|
stdin: |
|
|
declare -ai var=(1 2 3)
|
|
var[1]+=2
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Appending items to int indexed array"
|
|
stdin: |
|
|
declare -ai var=(1 2 3)
|
|
var+=(4 value 6)
|
|
declare -p var
|
|
|
|
- name: "Appending array to associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -A assoc_array=([a]=1 [b]=2 [c]=3)
|
|
assoc_array+=([d]=4 [e]=5 [f]=6)
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending array to declared-but-unset associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -A assoc_array
|
|
assoc_array+=([d]=4 [e]=5 [f]=6)
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending item to associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -A assoc_array=([a]=1 [b]=2 [c]=3)
|
|
assoc_array+=d
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending item to element of associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -A assoc_array=([a]=1 [b]=2 [c]=3)
|
|
assoc_array[b]+=2
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending item to element of int associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -Ai assoc_array=([a]=1 [b]=2 [c]=3)
|
|
assoc_array[b]+=2
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending items to int associative array"
|
|
stdin: |
|
|
source helpers.sh
|
|
declare -Ai assoc_array=([a]=1 [b]=2 [c]=3)
|
|
assoc_array+=([d]=4 [e]=value [f]=6)
|
|
stable_print_assoc_array assoc_array
|
|
|
|
- name: "Appending array to item"
|
|
stdin: |
|
|
var=x
|
|
var+=(a b c)
|
|
echo "var[*]: ${var[*]}"
|
|
declare -p var
|
|
|
|
- name: "Fill associative array"
|
|
stdin: |
|
|
declare -Ag myarray
|
|
|
|
myfunc() {
|
|
local myarg=$1 element
|
|
shift
|
|
for element in "$@"; do
|
|
echo "Setting: myarray[$element]=$myarg"
|
|
myarray[$element]="${myarg}${element}"
|
|
done
|
|
}
|
|
|
|
myfunc 'first' bunzip2 bzcat pbunzip2 pbzcat lbunzip2 lbzcat
|
|
|
|
- name: "Declare via array index"
|
|
stdin: |
|
|
declare -A assoc_array["key"]="value"
|
|
declare -p assoc_array
|
|
|
|
declare -a indexed_array[5]="value"
|
|
declare -p indexed_array
|
|
|
|
declare implicit_array[5]="value"
|
|
declare -p implicit_array
|
|
|
|
declare -A no_value_assoc_array["key"]
|
|
declare -p no_value_assoc_array
|
|
|
|
declare no_value_indexed_array[33]
|
|
declare -p no_value_indexed_array
|
|
|
|
- name: "Create array via index update"
|
|
stdin: |
|
|
i=0
|
|
my_array[i++]="c"
|
|
echo "0: i=$i array=${my_array[@]}"
|
|
my_array[i++]="b"
|
|
echo "1: i=$i array=${my_array[@]}"
|
|
my_array[i++]="a"
|
|
echo "2: i=$i array=${my_array[@]}"
|
|
|
|
- name: "Expansion of array body"
|
|
stdin: |
|
|
elements="a b c"
|
|
|
|
array1=(${elements})
|
|
declare -p array1
|
|
|
|
array2=("${elements}")
|
|
declare -p array2
|
|
|
|
- name: "Copy array"
|
|
stdin: |
|
|
src=(a b c)
|
|
|
|
dest1=("${src[*]}")
|
|
declare -p dest1
|
|
|
|
dest2=(${src[*]})
|
|
declare -p dest2
|
|
|
|
dest3=("${src[@]}")
|
|
declare -p dest3
|
|
|
|
dest4=(${src[@]})
|
|
declare -p dest4
|
|
|
|
- name: "Multi-line definition of array"
|
|
stdin: |
|
|
array=(
|
|
a
|
|
b
|
|
c
|
|
)
|
|
declare -p array
|
|
|
|
- name: "Dump values from non-existent array"
|
|
stdin: |
|
|
for key in ${NONEXISTENT[@]}; do
|
|
echo "@-Key: ${key}"
|
|
done
|
|
for key in "${NONEXISTENT[@]}"; do
|
|
echo "@-Quoted Key: ${key}"
|
|
done
|
|
|
|
for key in ${NONEXISTENT[*]}; do
|
|
echo "*-Key: ${key}"
|
|
done
|
|
for key in "${NONEXISTENT[*]}"; do
|
|
echo "*-Quoted Key: ${key}"
|
|
done
|
|
|
|
- name: "Use non-existent var in indexed array index"
|
|
stdin: |
|
|
declare -a myarray=(10)
|
|
echo "Value: ${myarray[$non_existent_var]}"
|
|
|
|
- name: "Use non-existent var in associative array index"
|
|
ignore_stderr: true
|
|
stdin: |
|
|
declare -A myarray=([0]="default" ["a"]="other")
|
|
echo "Value: ${myarray[$non_existent_var]}"
|
|
|
|
- name: "Nested array reference"
|
|
stdin: |
|
|
x=(2 3 4)
|
|
echo ${x[${x[0]}]}
|
|
|
|
- name: "Append array-resulting expansion to array"
|
|
stdin: |
|
|
declare -a otherarray=("a" "b" "c")
|
|
declare -a ourarray=()
|
|
|
|
ourarray+=("${otherarray[@]/a/x}")
|
|
declare -p otherarray
|
|
declare -p ourarray
|
|
|
|
- name: "Array declaration in a function"
|
|
stdin: |
|
|
outer() {
|
|
inner=()
|
|
if test true; then
|
|
echo true
|
|
else
|
|
echo false
|
|
fi
|
|
}
|
|
|
|
outer
|
|
|
|
- name: "Array element expansion with non-standard IFS"
|
|
stdin: |
|
|
IFS='|'
|
|
|
|
declare -a myarray=(abc 1 f)
|
|
echo "\"\${myarray[@]}\": ${myarray[@]}"
|
|
echo "\"\${myarray[*]}\": ${myarray[*]}"
|
|
echo "\${myarray[@]}:" ${myarray[@]}
|
|
echo "\${myarray[*]}:" ${myarray[*]}
|
|
|
|
#
|
|
# Field splitting applies to what an expansion produced, not to the literal text around it. A
|
|
# compound value's elements are separated by the parser on whitespace; an IFS character sitting
|
|
# in literal text is just a character.
|
|
#
|
|
- name: "Literal text in a compound value is not field-split"
|
|
stdin: |
|
|
IFS=,
|
|
arr=(a,b)
|
|
declare -p arr
|
|
|
|
- name: "A compound value field-splits an expansion but not the literal beside it"
|
|
stdin: |
|
|
IFS=,
|
|
v="p,q"
|
|
arr=(a,b $v keep,me)
|
|
declare -p arr
|
|
|
|
- name: "Empty array with newline"
|
|
stdin: |
|
|
declare -a myarray=(
|
|
)
|
|
|
|
- name: "Parenthesized arithmetic in array index assignment"
|
|
known_failure: true # TODO(tokenizer): #1211: '(' inside an assignment's subscript is tokenized as an operator
|
|
stdin: |
|
|
c[(1)]=x
|
|
declare -p c
|
|
i=1
|
|
d[(i+1)*2]=y
|
|
declare -p d
|
|
|
|
- name: "Compound assignment appends to an element with [key]+="
|
|
known_failure: true # TODO(parser): an element's += isn't parsed, so the word is taken as a value
|
|
stdin: |
|
|
a=(x y)
|
|
a+=([0]+=z)
|
|
declare -p a
|
|
declare -A m=([k]=v)
|
|
m+=([k]+=w [j]+=u)
|
|
declare -p m
|
|
declare -a d=(p q)
|
|
declare -a d+=([1]+=r)
|
|
declare -p d
|
|
|
|
- name: "Compound assignment evaluates an indexed array's subscripts"
|
|
known_failure: true # TODO(arrays): an element's subscript isn't evaluated as arithmetic
|
|
stdin: |
|
|
a=([1+1]=x)
|
|
declare -p a
|
|
i=1
|
|
declare -a b=([i+1]=y [i*5]=z)
|
|
declare -p b
|
|
|
|
#
|
|
# Ordering between value expansion and subscript evaluation. A shell expands an
|
|
# assignment's words before it evaluates any arithmetic subscript, so side effects
|
|
# in a subscript are not visible to the value being assigned.
|
|
#
|
|
- name: "Index arithmetic is evaluated after the value is expanded"
|
|
stdin: |
|
|
i=0
|
|
a[i++]=$i
|
|
declare -p a
|
|
echo "i=$i"
|
|
|
|
- name: "Append with an arithmetic subscript"
|
|
stdin: |
|
|
i=0
|
|
a[i++]=$i
|
|
a[i++]+=$i
|
|
declare -p a
|
|
echo "i=$i"
|
|
|
|
- name: "Associative subscripts are not arithmetically evaluated"
|
|
stdin: |
|
|
i=0
|
|
declare -A m
|
|
m[i++]=$i
|
|
declare -p m
|
|
echo "i=$i"
|
|
|
|
- name: "Associative subscript is expanded once in a plain assignment"
|
|
stdin: |
|
|
declare -A m
|
|
k='$(echo expanded-twice)'
|
|
m[$k]=v
|
|
declare -p m
|
|
|
|
#
|
|
# An empty subscript in a parameter reference is rejected while the word is parsed, before any
|
|
# array is consulted.
|
|
#
|
|
- name: "An empty subscript is a bad substitution"
|
|
known_failure: true # TODO: the word parser accepts an empty subscript and treats it as element 0
|
|
ignore_stderr: true
|
|
stdin: |
|
|
zz_a=(1 2 3)
|
|
echo "[${zz_a[]}]"
|
|
echo "status: $?"
|
|
|
|
- name: "Negative index into sparse indexed array"
|
|
stdin: |
|
|
b=(a b c d)
|
|
b[5]=q
|
|
echo "<${b[-2]}> <${b[-1]}>"
|
|
b[-2]=Z
|
|
b[-1]+=r
|
|
declare -p b
|
|
unset 'b[-3]'
|
|
declare -p b
|