Juan Cornejo
Juan Cornejo

Reputation: 41

How to modify 2d array in shell script

I have the following sample code for my shell script:

#!/bin/bash

x[1,1]=0
x[2,1]=1

echo "x[1,1]=${x[1,1]}"
echo "x[2,1]=${x[2,1]}"

for i in {1..2}; do
    x[$i,1]=${i}
    echo "loop$i x[$i,1]=${i}"
done

echo "x[1,1]=${x[1,1]}"
echo "x[2,1]=${x[2,1]}"

and I am expecting for x[1,1] to have the value of 1 and x[2,2] to have the value of 2.

But when I run the script the result is:

$ ./test3.sh    
x[1,1]=1    
x[2,1]=1    
loop1 x[1,1]=1    
loop2 x[2,1]=2
x[1,1]=2    
x[2,1]=2

I expect x[1,1] to retain the value of 1 but it happens to be 2 now. Is there something wrong with my script?

Upvotes: 1

Views: 1080

Answers (1)

John1024
John1024

Reputation: 113904

Bash does not have 2-D arrays. The best you can do is emulate them with associative arrays.

Add the following line to the beginning of your script:

declare -A x

This makes x into an associative array. When that is done, the script produces the output that you expect:

$ bash script
x[1,1]=0
x[2,1]=1
loop1 x[1,1]=1
loop2 x[2,1]=2
x[1,1]=1
x[2,1]=2

Bash indexed arrays

Unless declare -A is used, a bash array is just an indexed array. Let's define y as an indexed array:

$ y=()

Now, let's assign two values:

$ y[2,3]=1
$ y[22,3]=2

Now, let's use declare -p to find out what the contents of the array really are:

$ declare -p y
declare -a y='([3]="2")'

As you can see, there is only y[3]. The reason is that the index in an indexed array is subject to arithmetic expansion and, when given a list of comma-separated values, arithmetic expansion returns just the last one.

In other words, as far as bash is concerned, assignments to y[2,3] and y[22,3] are both just assignments to y[3]. The second assignment overwrites the first.

We can see this directly if we echo the results of arithmetic expansion:

$ echo $((3))
3
$ echo $((2,3))
3
$ echo $((22,3))
3

When given a list of comma-separated values, arithmetic expansion returns the last one. This is true even if the comma-separated list is a long one:

$ echo $((1+2,3*4,5,6,7,8))
8

It is always the last value which is returned.

Bash associative arrays

Let's examine what happens with associative arrays. Let's define z as an associative array and assign some values to it:

$ declare -A z
$ z[1,2]=1
$ z[3,4]=2
$ z["Jim Bob"]=3

Now, let's see what was stored in z:

$ declare -p z
declare -A z='([3,4]="2" ["Jim Bob"]="3" [1,2]="1" )'

This seems to be what you need.

Upvotes: 2

Related Questions