2

I want to create a dictionary in bash from a text file which looks like this:

H96400275|A
H96400276|B
H96400265|C
H96400286|D

Basically I want a dictionary like this from this file file.txt:

KEYS        VALUES
H96400275 = A
H96400276 = B
H96400265 = C
H96400286 = D

I created following script:

#!/bin/bash
declare -a dictionary

while read line; do 

  key=$(echo $line | cut -d "|" -f1)
  data=$(echo $line | cut -d "|" -f2)
  dictionary[$key]="$data"
done < file.txt


echo ${dictionary[H96400275]}

However, this does not print A, rather it prints D. Can you please help ?

lakhujanivijay
  • 107
  • 2
  • 11
  • Closely related: https://stackoverflow.com/questions/38964946/reading-key-value-parameters-from-a-file-into-a-shell-script – oguz ismail Nov 19 '19 at 07:07
  • 1
    Don't create an additional subshell for each call to `cut` simply use *parameter expansions* `key="${line%|*}"` and `data="${line#*|}"`, or just `dictionary[${line%|*}]=${line#*|}` (after fixing the `-a` to `-A` problem) – David C. Rankin Nov 19 '19 at 07:23
  • There is more than one remark on this post! Please consider [smart oguz ismail's answer](https://stackoverflow.com/a/58928414/1765658) – F. Hauri - Give Up GitHub Nov 19 '19 at 08:39

3 Answers3

7

Associative arrays (dictionaries in your terms) are declared using -A, not -a. For references to indexed (ones declared with -a) arrays' elements, bash performs arithmetic expansion on the subscript ($key and H96400275 in this case); so you're basically overwriting dictionary[0] over and over, and then asking for its value; thus D is printed.

And to make this script more effective, you can use read in conjunction with a custom IFS to avoid cuts. E.g:

declare -A dict

while IFS='|' read -r key value; do
    dict[$key]=$value
done < file

echo "${dict[H96400275]}"

See Bash Reference Manual § 6.7 Arrays.

oguz ismail
  • 1
  • 16
  • 47
  • 69
5

the only problem is that you have to use -A instead of -a

      -a     Each name is an indexed array variable (see Arrays above).
      -A     Each name is an **associative** array variable (see Arrays above).
torbatamas
  • 1,236
  • 1
  • 11
  • 21
0

What you want to do is so named associative array. And to declare it you need to use command:

declare -A dictionary
Romeo Ninov
  • 6,538
  • 1
  • 22
  • 31