Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I populate a bash associative array with command output?

Tags:

bash

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=()
like image 632
Ed Morton Avatar asked Sep 09 '16 18:09

Ed Morton


People also ask

How do you use associative arrays in bash?

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.

How do you echo an associative array in bash?

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[@]} .

Does bash support associative arrays?

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.

What is the command to create an associative array in bash declare?

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…. )


1 Answers

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" )'
like image 121
anubhava Avatar answered Oct 05 '22 02:10

anubhava