Thanatos
Thanatos

Reputation: 44256

Bash array assignment fails if you declare the array in advance

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. Only string 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

Answers (6)

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

dragon788
dragon788

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

vijayalakshmi d
vijayalakshmi d

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

influxd
influxd

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

anubhava
anubhava

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

Jonathan Leffler
Jonathan Leffler

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

Related Questions