2

How do I use dynamic array variable names in bash?

numCounter=1
arrayIndex=0

arr$numCounter[$arrayIndex]=0
((arrayIndex++))
arr$numCounter[$arrayIndex]=1

What I'm hoping this will return is

arr1[0] is 0
arr1[1] is 1

What I want to do is have n number of arrays and store x number of files in each array.

var1=1
arrayFolder(var1)[index0] = file1
arrayFolder(var1)[index1] = file2
arrayFolder(var1)[index2] = file3

var1=2  
arrayFolder(var1)[index0] = file4
arrayFolder(var1)[index1] = file5
arrayFolder(var1)[index2] = file6

Expected result
arrayFolder1[0]=file1
arrayFolder1[1]=file2
arrayFolder1[2]=file3
arrayFolder2[0]=file4
arrayFolder2[1]=file5
arrayFolder2[2]=file6

How can I achieve this?

theking963
  • 2,223
  • 7
  • 28
  • 42
  • Didn't you ask this and get a duplicate question pointer very recently? It would do some good to show how you tried to apply that answer, and how that failed. – Charles Duffy Feb 12 '18 at 17:07
  • `declare "arr$numCounter[$arrayIndex]"=0; ((arrayIndex++)); declare "arr$numCounter[$arrayIndex]"=1` should work – anubhava Feb 12 '18 at 17:09
  • (...ahh, [assign to a bash array indirectly by dynamically constructed variable](https://stackoverflow.com/questions/23819839/assign-to-a-bash-array-variable-indirectly-by-dynamically-constructed-variable) is the answer I closed your prior question with. This one is *much* better asked than your prior question yesterday -- and *thank you* for putting in the effort; since you've put in that effort, I'm assuming you also have a distinct and unique question, but it's still not obvious to me where this question isn't covered by the prior one; could you [edit] to make that more explicit?) – Charles Duffy Feb 12 '18 at 17:15
  • (To be clear -- this is sufficiently well-asked that if even if it does end up getting closed as dupe, I'd ask you not to delete it -- good duplicates add value to the site insofar as they set up additional search terms that direct someone to whichever question we've decided is the canonical instance). – Charles Duffy Feb 12 '18 at 17:29

3 Answers3

4

Using bash 4.3, declare -n aliasName=destVarName will make aliasName refer to destVarName, even for arrays; thus permitting any kinds of assignment, dereferencing, &c. you would otherwise use.

#!/usr/bin/env bash
#          ^^^^^^^^ - Use bash version from PATH; on MacOS, this should be newer
#                     than the system one if MacPorts, Homebrew, etc. is installed.

case $BASH_VERSION in
  ''|[1-3]*|4.[0-2]*) echo "This code requires bash 4.3 or newer" >&2; exit 1;;
esac

# to make "index0", "index1", &c. valid indexes, our arrays need to be associative
declare -A arrayFolder1 arrayFolder2

var1=1
declare -n curArrayFolder=arrayFolder$var1
curArrayFolder[index0]=file1
curArrayFolder[index1]=file2
curArrayFolder[index2]=file3
unset -n curArrayFolder

var1=2  
declare -n curArrayFolder=arrayFolder$var1
curArrayFolder[index0]=file4
curArrayFolder[index1]=file5
curArrayFolder[index2]=file6
unset -n curArrayFolder

...will properly result in a situation where:

declare -p arrayFolder1 arrayFolder2

emits as output:

declare -A arrayFolder1=([index0]="file1" [index1]="file2" [index2]="file3" )
declare -A arrayFolder2=([index0]="file4" [index1]="file5" [index2]="file6" )

If you want to try to cut down the number of commands needed to switch over which folder is current, consider a function:

setCurArrayFolder() {
  declare -p curArrayFolder &>/dev/null && unset -n curArray
  declare -g -n curArrayFolder="arrayFolder$1"
  var1=$1
}

Then the code becomes:

setCurArrayFolder 1
curArrayFolder[index0]=file1
curArrayFolder[index1]=file2
curArrayFolder[index2]=file3

setCurArrayFolder 2
curArrayFolder[index0]=file4
curArrayFolder[index1]=file5
curArrayFolder[index2]=file6
Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • I was missing the declare -A and unset. How can I read the array? I tried `echo ${curArrayFolder1[0]}` and `echo ${arrayFolder1[0]}` and there's no value associated with it. – theking963 Feb 12 '18 at 18:31
  • In the above examples, it's actually `${curArrayFolder1[index0]}` where the value is set, as opposed to `${curArrayFolder1[0]}` (since "index0" was the example you used in the question). `declare -A` isn't essential to indirect array assignment, but it *is* essential to be able to have non-numeric array indices, such as `index0` instead of `0`. – Charles Duffy Feb 12 '18 at 18:50
  • I'm using a variable for array indexes. Numeric array indices seems to work. Thanks this worked. – theking963 Feb 12 '18 at 20:02
0

You can use declare and variable indirection.

#!/bin/bash
numCounter=1
arrayIndex=0

assign () {
    sub="sub$1[$2]"
    declare -g $sub=$3
}

get () {
    r="sub$1[$2]"
    echo "${!r}"
}

assign $numCounter $arrayIndex 0

((arrayIndex++))
assign $numCounter $arrayIndex 1

((numCounter++))
assign $numCounter 0 2

echo $(get 1 0) is 0
echo $(get 1 1) is 1
echo $(get 2 0) is 2
choroba
  • 231,213
  • 25
  • 204
  • 289
0

A multidimensional array can be emulated by using an associative array with multiple values concatenated into each key. You could, for instance, join two numbers with a colon ,:

declare -A arrayFolder

var1=1
arrayFolder[$var1,$index0]=file1
arrayFolder[$var1,$index1]=file2
arrayFolder[$var1,$index2]=file3

var1=2  
arrayFolder[$var1,$index0]=file4
arrayFolder[$var1,$index1]=file5
arrayFolder[$var1,$index2]=file6

Result:

$ declare -p arrayFolder
declare -A arrayFolder='([2,0]="file4" [2,1]="file5" [2,2]="file6" [1,2]="file3" [1,1]="file2" [1,0]="file1" )'
John Kugelman
  • 349,597
  • 67
  • 533
  • 578