2

I have a file that looks like this:

stringtests (6 tests)
alphatests (1 tests)
arraytests (100 tests)

I can extract and translate into:

["stringtests"]="6"
["alphatests"]="1"
["arraytests"]="100"

I place these in a variable ("tests"):

~> tests="[\"stringtests\"]=\"6\" [\"alphatests\"]=\"1\" [\"arraytests\"]=\"100\""

Then I try to put them in an associative array using the variable I get an error:

~> declare -A arr=( $tests )
-bash: arr: ["stringtests"]="6": must use subscript when assigning associative array
-bash: arr: ["alphatests"]="1": must use subscript when assigning associative array
-bash: arr: ["arraytests"]="100": must use subscript when assigning associative array

"eval" doesn't work either:

declare -A arr=( $(eval echo $tests) )
-bash: arr: [stringtests]=6: must use subscript when assigning associative array
-bash: arr: [alphatests]=1: must use subscript when assigning associative array
-bash: arr: [arraytests]=100: must use subscript when assigning associative array

But, if I put the values directly it works:

~> declare -A arr=( ["stringtests"]="6" ["alphatests"]="1" ["arraytests"]="100" )
~> echo ${arr[@]}
1 100 6
~> echo ${!arr[@]}
alphatests arraytests stringtests

Is it even possible to do this?

Sean Walton
  • 123
  • 2
  • 11
  • Need eval before declare not in the subshell.`eval declare -A arr=( $tests )`. Fails because `=` is evaluated before variable expansion so array sees `["stringtests"]="6"` as a single string. – 123 Oct 31 '17 at 16:34
  • @123, eh? `eval` can be avoided entirely here, and when it *can* be avoided it *should*. – Charles Duffy Oct 31 '17 at 17:26
  • @CharlesDuffy Just pointing out the issue with their command, not suggesting it was the best option. – 123 Oct 31 '17 at 17:37

2 Answers2

4

Replace

declare -A arr=( $tests )

with

declare -A arr='('$tests')'

tests="[\"stringtests\"]=\"6\" [\"alphatests\"]=\"1\" [\"arraytests\"]=\"100\""
declare -A arr='('$tests')'
declare -p arr

Output:

declare -A arr='([alphatests]="1" [arraytests]="100" [stringtests]="6" )'
Cyrus
  • 84,225
  • 14
  • 89
  • 153
1

I would avoid the temp variable altogether, and populate the array while you're parsing the file

declare -A arr
while IFS= read -r line; do 
    # bash regex: the literal bits are quoted
    if [[ $line =~ (.+)" ("([0-9]+) ]]; then 
        arr["${BASH_REMATCH[1]}"]="${BASH_REMATCH[2]}"
    fi
done < file
declare -p arr
declare -A arr='([alphatests]="1" [arraytests]="100" [stringtests]="6" )'
glenn jackman
  • 238,783
  • 38
  • 220
  • 352