-1

Update

As multiple comments have pointed out, associative arrays are not available / supported in Bash 2 or Bash 3. Closing this thread. See below for how we solved the Problem that we were trying to solve using Associative Arrays.

Problem

We have a Project where a Bash Associative Array is declared in a File, say def.sh, like so

#!/bin/bash

declare -a map=(

    ["Key_A"]='Val_A'

    ["Key_B"]='VAL_B'

)

This File is sourced on Terminal with source def.sh, and then individual elements are accessed like so

export var_a="xyz"

var_b="${map[${var_a}]}"

Reason why this is done this way has something to do with the in-house Systems that we are working with and requirements of Project.

This was working fine earlier when the Map had only one entry.

When we added a second entry to the map (i.e. when it looks like snippet above), this map always returns the value of second / last entry / pair.

That is, even if we do

export var_a="Key_A"

var_b="${map[${var_a}]}"

echo ${var_b} gives VAL_B. Needless to say, "${map[KEY_B]}" still gives VAL_B.

We have tried without Parameter substitutions (i.e. "${map[KEY_A]}") with and without quotes, result is same.

Any idea on why this might be happening?

Edit :

For

Have tried with declare -A map=( as well, result is

bash: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

help declare output :

declare: declare [-afFirtx] [-p] [name[=value] ...]
    Declare variables and/or give them attributes.  If no NAMEs are
    given, then display the values of variables instead.  The -p option
    will display the attributes and values of each NAME.
    
    The flags are:
    
      -a    to make NAMEs arrays (if supported)
      -f    to select from among function names only
      -F    to display function names (and line number and source file name if
        debugging) without definitions
      -i    to make NAMEs have the `integer' attribute
      -r    to make NAMEs readonly
      -t    to make NAMEs have the `trace' attribute
      -x    to make NAMEs export
    
    Variables with the integer attribute have arithmetic evaluation (see
    `let') done when the variable is assigned to.
3
  • 2
    In previous comment (already removed), the OP mentioned that he/she is using bash 2 or bash 3, which do not support associative array. Without declare -A, bash array is indexed by integers. Then declare -a map=( ["Key_A"]='Val_A' ["Key_B"]='VAL_B' ) is equivalent to declare -a map=( [0]='Val_A' [0]='VAL_B' ). That is why the last value only remains. You'll need to modify the code to use integers as index (as far as you stick to bash 2 or 3). Commented Sep 5, 2023 at 7:17
  • I’m voting to close this question because OP posted they will close the question as solved due to bash versioning of syntax. Commented Sep 5, 2023 at 14:02
  • Did my answer work for you? Commented Sep 10, 2023 at 18:33

3 Answers 3

1

Arrays which have strings as indexes are known as associative arrays. This type of array however is not supported in the bash version that you are using (3.2)

In bash 4, you would use:

$ declare -A map=(["Key_A"]='Val_A' ["Key_B"]='VAL_B')
$ export var_a="Key_A"
$ echo "${map[${var_a}]}"
Val_A
Sign up to request clarification or add additional context in comments.

5 Comments

Does your bash version support associative arrays? What does help declare say?
@D159 You can use declare -p map to see what map is. If it says declare -a map=([0]="VAL_B"), you have a numerically indexed array (which is what your original code defines). If you replace -a with -A, it should say declare -A map=([Key_B]="VAL_B" [Key_A]="Val_A" ), which is an associative array.
bash: declare: -A: invalid option declare: usage: declare [-afFirtx] [-p] [name[=value] ...]
@D159 Looks like bash 3 doesn't have associative arrays
@D159 Associative arrays were added in bash v4.0; see BashFAQ #61.
0

The example you provided doesn't declare an associative array in Bash; it declares a regular indexed array.


Associative arrays in Bash use the declare -A syntax, not declare -a. - (Reference: GNU)

#!/bin/bash

declare -A map

map["Key_A"]='Val_A'
map["Key_B"]='VAL_B'

export var_a="Key_A"
var_b="${map[${var_a}]}"
echo "${var_b}" # This should give 'Val_A'

Earlier than Bash 4.0 - There could be a better approach to this

#!/bin/bash

# Define a function to get the value for a given key
get_value() {
    case "$1" in
        "Key_A") echo "Val_A";;
        "Key_B") echo "VAL_B";;
        *) echo "Key not found: $1";;
    esac
}


export var_a="Key_A"
var_b=$(get_value "$var_a")
echo "$var_b"  # This should give 'Val_A'

export var_a="Key_B"
var_b=$(get_value "$var_a")
echo "$var_b"  # This should give 'VAL_B'

3 Comments

Tried that, same result. Added result for this in the description of Problem. Note that we are souring the File containing the Array, not declaring the Array as a command on shell.
I have updated the answer, please try now!
Ok I see you're running on Bash ealier 4.0 - you need to define two indexed array - one for key and one for value and iterate using some function to search value based on the key - that way you can achieve it.
0

We solved the Problem by changing the way Variables are defined and accessed.

Problem was really about creating Variables whose names depend on values of other variables.

We first tried to solve this by using Associative Arrays whose names are static, and using Strings as Keys for accessing values in the arrays (these Strings are in turn the values of other variables).

Now we have converted the entries in Associative Arrays to normal Variables.

That is, before we had

#!/bin/bash

declare -a map=(

    ["Key_A"]='Val_A'

    ["Key_B"]='VAL_B'

)

Now we have

#!/bin/bash

export map_Key_A='Val_A'
export map_Key_B='VAL_B'

Now we create intermediate variables like so

some_var="some_val"

key_name="map_${some_var}" 

And then do

source def.sh
val=${!key_name}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.