112

I am trying to create a dictionary of key value pair using Bash script. I am trying using this logic:

declare -d dictionary
defaults write "$dictionary" key -string "$value"

...where $dictionary is a variable, but this is not working.

Is there a way to create key-value pairs in Bash script?

mfaani
  • 33,269
  • 19
  • 164
  • 293
RKS
  • 1,333
  • 2
  • 12
  • 12

6 Answers6

201

In bash version 4 associative arrays were introduced.

declare -A arr

arr["key1"]=val1

arr+=( ["key2"]=val2 ["key3"]=val3 )

The arr array now contains the three key value pairs. Bash is fairly limited what you can do with them though, no sorting or popping etc.

for key in ${!arr[@]}; do
    echo ${key} ${arr[${key}]}
done

Will loop over all key values and echo them out.

Note: Bash 4 does not come with Mac OS X because of its GPLv3 license; you have to download and install it. For more on that see here

mfaani
  • 33,269
  • 19
  • 164
  • 293
peteches
  • 3,447
  • 1
  • 13
  • 15
  • 37
    It is important to note that Bash 4 does not come with Mac OS X because of its GPLv3 license; you have to download and install it. (Apple still ships Bash 3.2.) – PleaseStand Jan 17 '13 at 02:22
  • 7
    There's a con here: The iteration is not ordered by insertion order. – AlikElzin-kilaka Jul 17 '16 at 13:45
  • definitely needs bash version 4. Otherwise declare -A does not work. Mac comes with bash 3.2 – Mamun Dec 17 '19 at 18:32
  • 4
    It's not because of the GPLv3 license but because Apple doesn't want to use GPLv3 licensed software. So it's nothing wrong with GPLv3 license but something wrong with Apple, I assume. – FullStack Alex Apr 28 '20 at 11:22
44

If you can use a simple delimiter, a very simple oneliner is this:

for i in a,b c_s,d ; do 
  KEY=${i%,*};
  VAL=${i#*,};
  echo $KEY" XX "$VAL;
done

Hereby i is filled with character sequences like "a,b" and "c_s,d". each separated by spaces. After the do we use parameter substitution to extract the part before the comma , and the part after it.

yunque
  • 625
  • 1
  • 8
  • 18
math
  • 8,514
  • 10
  • 53
  • 61
12

In bash, we use

declare -A name_of_dictonary_variable

so that Bash understands it is a dictionary.

For e.g. you want to create sounds dictionary then,

declare -A sounds

sounds[dog]="Bark"

sounds[wolf]="Howl"

where dog and wolf are "keys", and Bark and Howl are "values".

You can access all values using : echo ${sounds[@]} OR echo ${sounds[*]}

You can access all keys only using: echo ${!sounds[@]}

And if you want any value for a particular key, you can use:

${sounds[dog]}

this will give you value (Bark) for key (dog).

andrej
  • 4,518
  • 2
  • 39
  • 39
Ruchir Dixit
  • 121
  • 1
  • 4
4

For persistent key/value storage, you can use kv-bash, a pure bash implementation of key/value database available at https://github.com/damphat/kv-bash

Usage

git clone https://github.com/damphat/kv-bash
source kv-bash/kv-bash

Try create some permanent variables

kvset myName  xyz
kvset myEmail xyz@example.com

#read the varible
kvget myEmail

#you can also use in another script with $(kvget keyname)
echo $(kvget myEmail)
Pineda
  • 7,435
  • 3
  • 30
  • 45
andrej
  • 4,518
  • 2
  • 39
  • 39
2
Using an example above this is what I did

#!/bin/sh
lookup_vht_index() {
for i in VHT20,0 VHT40,1 VHT80,2 VHT160,3 ; do
  KEY=${i%,*};
  VAL=${i#*,};
#  echo $KEY" XX "$VAL;
  [ "$1" = "$KEY" ] && echo $VAL
done
}

lookup_vht_name() {
for i in 0,VHT20 1,VHT40 2,VHT80 3,VHT160 ; do
  KEY=${i%,*};
  VAL=${i#*,};
#  echo $KEY" XX "$VAL;
  [ "$1" = "$KEY" ] && echo $VAL
done
}


echo "VHT20="$(lookup_vht_index "VHT20")
echo "2="$(lookup_vht_name 2)
Craig
  • 21
  • 1
1

in older bash (or in sh) that does not support declare -A, following style can be used to emulate key/value

# key
env=staging


# values
image_dev=gcr.io/abc/dev
image_staging=gcr.io/abc/stage
image_production=gcr.io/abc/stable

img_var_name=image_$env

# active_image=${!var_name}
active_image=$(eval "echo \$$img_var_name")

echo $active_image
romanlv
  • 1,432
  • 15
  • 15