Reputation: 44256
This works:
$ BAR=(a b c)
$ echo "${BAR[1]}"
b
This, however, doesn't:
$ declare -A FOO
$ FOO=(a b c)
bash: FOO: a: must use subscript when assigning associative array
bash: FOO: b: must use subscript when assigning associative array
bash: FOO: c: must use subscript when assigning associative array
The docs claim the subscript is optional:
Arrays are assigned to using compound assignments of the form
name=(value1 ... valuen)
, where each value is of the form[subscript]=string
. Onlystring
is required.
What about the use of declare
changes the syntax of array assignment here? Why does hinting bash about the type of the variable with declare
change things? (Why does declare
exist at all — if I assign an array to a variable, then the variable is an array… no?)
Upvotes: 15
Views: 24270
Reputation: 707
Be careful, in my case I was getting this error because before and after the =
I was adding a space.
declare -A table_queries=(
["cluster"] = "select * from cluster where report_version_id = $REPORT_VERSION_ID"
) # Incorrect
declare -A table_queries=(
["cluster"]="select * from cluster where report_version_id = $REPORT_VERSION_ID"
) # Correct
Upvotes: 1
Reputation: 3901
Per the other answers this is the difference between associative (key=value pairs) and indexed (index 0-infinity, value) arrays in Bash.
Now if you want to do a clever trick by building up an indexed array and converting it to an associative array later this is possible, though keep in mind the "values" that get converted to "keys" must be unique in the array or they will get overwritten unless you do some tracking of how many times a given "value" was seen and insert the indices into an array of values for each "key".
https://unix.stackexchange.com/a/177589
declare -a array1
array1=() # Empty the array to avoid repeated runs introducing side effects
# Using `+=($stuff)` adds to an array, using `+=$stuff` concatenates text
# if $stuff might have spaces, double quote it! or just always quote!
# see the tricky 'bar baz' with a space
for eachword in foo 'bar baz' fizzbuzz; do array1+=("$eachword"); done
# Make SURE you quote the array when looping over in case values have spaces
for eachword in "${array1[@]}"; do echo "$eachword"; done
declare -A map # required: declare explicit associative array
for key in "${!array1[@]}" # expand the array indexes to a list of words
do
# Check uniqueness note
map[${array1[$key]}]="$key" # exchange the value ${array1[$key]} with the index $key
done
# Debug printing the new associative array
for eachkey in "${!map[@]}"; do echo "${eachkey}"; done
for eachvalue in "${map[@]}"; do echo "${eachvalue}"; done
a=fizzbuzz
[[ -n "${map[$a]}" ]] && printf '%s is in array\n' "$a"
# UNIQUENESS NOTE
# Add code before the map if you won't have unique "keys"
# It should check if the $array1[$key] already exists and make its "value" an array where you append every new index where it existed
# NOTE: there may be some limitations with nested arrays in Bash
Upvotes: 1
Reputation: 726
You have used -A option which is creating associating array variable Instead, you should try creating array variable by using option -a.
bash-3.2$ declare -a BOO
bash-3.2$ BOO=(a b c)
bash-3.2$
bash-3.2$ echo "${BOO[1]}"
b
bash-3.2$ echo "${BOO[2]}"
c
bash-3.2$
Upvotes: 1
Reputation: 536
$ declare -A FOO
This is declaring an associative array. Note the difference in case, -a
is used to declare an (indexed) array.
$ declare -a FOO
Upvotes: 6
Reputation: 784938
You cannot initialize simple index based array declared with -A
like that.
Use this:
declare -A foo
foo=( [x]="A" [y]="B" [z]="C" )
OR just:
declare -A foo=( [x]="A" [y]="B" [z]="C" )
To use index based indices in an associative array use:
declare -A foo=( [0]="a" [1]="b" [2]="c" )
Upvotes: 5
Reputation: 753525
declare -a
declares an array indexed by integers.
declare -A
declares an associative array indexed by strings.
You have to use:
FOO=([1]="a" [2 or 3]="b or c")
or similar notations to assign to the associative array, and:
echo "${FOO[2 or 3]}"
to access them.
Upvotes: 21