I'm trying to populate an associative array with the output of a command. I can do it without a command as:
$ declare -A x=( [first]=foo [second]=bar )
$ echo "${x[first]}, ${x[second]}"
foo, bar
and I can populate a non-associative array with command output as:
$ declare y=( $(echo 'foo bar') )
$ echo "${y[0]}, ${y[1]}"
foo, bar
but when I try to build on both of the above to create a statement that will populate an associative array from a command, I get the following error message:
$ declare -A z=( $(echo '[first]=foo [second]=bar') )
-bash: z: $(echo '[first]=foo [second]=bar'): must use subscript when assigning associative array
Why am I getting that error message and what is the correct syntax to populate an associative array with the output of a command? I am trying to avoid using eval
for the usual reasons, do not want to use a temp file, and of course echo
is just being used as an example of a command that produces the effect in question, the real command will be more complicated.
So, based on a couple of the answers below, it looks like it was just my quoting that was a problem:
$ declare -A z="( $(echo '[first]=foo [second]=bar') )"
$ echo "${z[first]}, ${z[second]}"
foo, bar
and with spaces in the indices and values:
$ declare -A z="( $(echo '[first field]="foo with space" [second]="space bar"') )"
$ echo "${z[first field]}, ${z[second]}"
foo with space, space bar
EDIT in response to a question in the comments about why the quotes are necessary (How do I populate a bash associative array with command output?) - I don't exactly know but maybe someone else can explain using the results of this script as reference (not expecting the specified indices to be used in the indexed arrays, they're just part of the strings being populated as the array values):
$ cat tst.sh
#!/bin/env bash
set -x
printf 'Indexed, no quotes\n'
declare -a w=( $(echo '[first]=foo [second]=bar') )
declare -p w
printf '\n---\n'
printf 'Indexed, with quotes\n'
declare -a x="( $(echo '[first]=foo [second]=bar') )"
declare -p x
printf '\n---\n'
printf 'Associative, no quotes\n'
declare -A y="( $(echo '[first]=foo [second]=bar') )"
declare -p y
printf '\n---\n'
printf 'Associative, with quotes\n'
declare -A z=( $(echo '[first]=foo [second]=bar') )
declare -p z
.
$ ./tst.sh
+ printf 'Indexed, no quotes\n'
Indexed, no quotes
+ w=($(echo '[first]=foo [second]=bar'))
++ echo '[first]=foo [second]=bar'
+ declare -a w
+ declare -p w
declare -a w=([0]="[first]=foo" [1]="[second]=bar")
+ printf '\n---\n'
---
+ printf 'Indexed, with quotes\n'
Indexed, with quotes
++ echo '[first]=foo [second]=bar'
+ declare -a 'x=( [first]=foo [second]=bar )'
+ declare -p x
declare -a x=([0]="bar")
+ printf '\n---\n'
---
+ printf 'Associative, no quotes\n'
Associative, no quotes
++ echo '[first]=foo [second]=bar'
+ declare -A 'y=( [first]=foo [second]=bar )'
+ declare -p y
declare -A y=([second]="bar" [first]="foo" )
+ printf '\n---\n'
---
+ printf 'Associative, with quotes\n'
Associative, with quotes
+ z=($(echo '[first]=foo [second]=bar'))
./tst.sh: line 24: z: $(echo '[first]=foo [second]=bar'): must use subscript when assigning associative array
+ declare -A z
+ declare -p z
declare -A z=()
An associative array can be declared in bash by using the declare keyword and the array elements can be initialized at the time of array declaration or after declaring the array variable. The following script will create an associative array named assArray1 and the four array values are initialized individually.
The values of an associative array are accessed using the following syntax ${ARRAY[@]} . To access the keys of an associative array in bash you need to use an exclamation point right before the name of the array: ${! ARRAY[@]} .
Bash provides one-dimensional indexed and associative array variables. Any variable may be used as an indexed array; the declare builtin will explicitly declare an array. There is no maximum limit on the size of an array, nor any requirement that members be indexed or assigned contiguously.
Declaring an Associative Array and Initialize It A quick alternative is to declare and initialize an array in a single bash command as follows: $ declare -A ArrayName=( [key1]=Value1 [key2]=Value2 [Key3]=Value3…. )
Here is a traditional while loop approach to populate an associative array from a command's output:
while IFS= read -r; do
declare -A z+="( $REPLY )"
done < <(printf '[first]=foo [second]=bar\n[third]=baz\n')
# check output
$> echo "${z[first]}, ${z[second]}, ${z[third]}"
foo, bar, baz
# or declare -p
$> declare -p z
declare -A z='([third]="baz" [second]="bar" [first]="foo" )'
EDIT: Your original attempt will also work with proper quotes:
$> unset z
$> declare -A z="( $(echo '[first]=foo [second]=bar') )"
$> declare -p z
declare -A z='([second]="bar" [first]="foo" )'
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With