Sun, 26 Aug 2007

Emulating two-dimensional (or even multi-dimensional) arrays in bash

Ever needed to use arrays of two or more dimensions but got stuck on Bash limited array support which provides only 1 dimension?

There is a trick that let's you dynamically create variable names. Using this, you can emulate additional dimensions.


::Read from here

Here's a simple example for an array with 2 dimensions:

#set the value of my_array[i][j] where i = 25 and j = 10 to "value"

var="my_array25-10"
#or like this: I=25;J=10;var="my_array$I-$J"

declare $var="value"
#retrieve the value of my_array[i][j] where i = 5 and j = 10
var="my_array5-10"
#or like this: I=5;J=10;var="my_array$I-$J"
echo ${!var}

Thanks to the guys from #bash on freenode for their help and their excellent bash faq

Comments

Beware, when you use declare then your variables become scoped! (unlike "normal" variables in bash)

does not work for me.

I think what you mean is more something like that:

venus tools # var=(my_array5-10 a) ; echo ${!var[*]}
0 1
venus tools # var=(my_array5-10 a) ; var[33]="lala" ; echo ${!var[*]}
0 1 33
venus tools #

this is possible since bash-3.0 i think.

cheers

var="my_array25-10"; declare $var="value"
-bash: declare: `my_array25-10=value': not a valid identifier

bash 3.1 ... what now?

What if you placed the value in the array and just referenced it ?

Like if you had four values to save reserve array[0-4] for it then array[5-8] for next value ?
Or create two, three or four + arrays ?

Anonymous, if I understand correctly you basically mean to store entries as foo[k*i + j] where k<=max(j). this works, sure. Though it is imho a bit less flexible.
Using multiple array variables, and considering the variable name one of the dimensions, that seems like a good alternative approach indeed.

If you get "not a valid identifier" this is because of the '-' character which is not allowed in variable names (anymore?). With an underscore it works ('_')

This is a code snippet of some syntax checking I am doing. I am not including all the code that needs to be written to get this to work. If you have one dimension of the array that needs to represent the disk group and the second dimension to be the slices in each of the disk group you could do something similar to this:

DG[1]=rootdg DG[2]=appdg DG[3]=datadg i=1 j=1 Slice1=root Slice2=var eval `echo ${DG[$i]}'[$j]'=$Slice1` eval `echo ${DG[1]}'[2]'=$Slice2` eval print `eval "echo \$\{${DG[$i]}'[$j]'\}"`

Note that the eval and echo statements and the double eval require some pretty tricky syntax in korn shell. there may be better ways to do this, for sure. But initially it works. If I run the code, the result is "root"

(provided none of the syntax gets munged by the web posting I do.) :)


Name:


E-mail:


URL:


Comment:


What is the first name of the guy blogging here?


This comment form is pretty crude. Make sure mandatory fields are entered correctly.
Basic html tags (a,i,b, etc) are allowed, others are sanitized