mikechambers
mikechambers

Reputation: 3089

Dynamically creating associative arrays in bash

I have a variable ($OUTPUT) that contains the following name / value pairs:

member_id=4611686018429783292
platform=Xbox
platform_id=1
character_id=2305843009264966985
period_dt=2020-11-25 20:31:14.923158 UTC
mode=all Crucible modes
mode_id=5
activities_entered=18
activities_won=10
activities_lost=8
assists=103
kills=233
average_kill_distance=15.729613
total_kill_distance=3665
seconds_played=8535
deaths=118
average_lifespan=71.72269
total_lifespan=8463.277
opponents_defeated=336
efficiency=2.8474576
kills_deaths_ratio=1.9745762
kills_deaths_assists=2.411017
suicides=1
precision_kills=76
best_single_game_kills=-1

Each line ends with \n.

I want to loop through them, and parse them into an associative array, and the access the values in the array by the variable names:

while read line
do
    key=${line%%=*}
    value=${line#*=}

    echo $key=$value
    data[$key]="$value"

done < <(echo "$OUTPUT")

#this always prints the last value
echo ${data['seconds_played']}

This seems to work, i.e. key/value print the right values, but when I try to pull any values from the array, it always returns the last value (in this case -1).

I feel like im missing something obvious, but have been banging my head against it for a couple of hours.

UPDATE: My particular issue is I'm running a version of bash (3.2.57 on OSX) that doesn't support associative arrays). I'll mark the correct answer below.

Upvotes: 3

Views: 995

Answers (2)

KamilCuk
KamilCuk

Reputation: 141883

Without declare -A data, then data is a normal array. In normal arrays expressions in [here] first undergo expansions, then arithmetic expansion. Inside arithmetic expansion unset variables are expanded to 0. You are effectively only just setting data[0]=something, because data[$key] is data[seconds_played] -> variable seconds_played is not defined, so it expands to data[0]

Add declare -A data and it "should work". You could also just:

declare -A data
while IFS== read -r key value; do
    data["$key"]="$value"
done <<<"$OUTPUT"

Upvotes: 4

markp-fuso
markp-fuso

Reputation: 35356

Try declaring data as an associative array before populating it, eg:

$ typeset -A data                   # declare as an associative array
$ while read line
do
    key=${line%%=*}
    value=${line#*=}

    echo $key=$value
    data[$key]="$value"

done <<< "${OUTPUT}"

$ typeset -p data
declare -A data=([mode]="all Crucible modes" [period_dt]="2020-11-25 20:31:14.923158 UTC" [deaths]="118" [best_single_game_kills]="-1" [efficiency]="2.8474576" [precision_kills]="76" [activities_entered]="18" [seconds_played]="8535" [total_lifespan]="8463.277" [average_lifespan]="71.72269" [character_id]="2305843009264966985" [kills]="233" [activities_won]="10" [average_kill_distance]="15.729613" [activities_lost]="8" [mode_id]="5" [assists]="103" [suicides]="1" [total_kill_distance]="3665" [platform]="Xbox" [kills_deaths_ratio]="1.9745762" [platform_id]="1" [kills_deaths_assists]="2.411017" [opponents_defeated]="336" [member_id]="4611686018429783292" )

$ echo "${data['seconds_played']}"
8535

Upvotes: 3

Related Questions