Mike
Mike

Reputation: 31

How to substitute array element with a variable in bash?

I've got about 10 arrays like so:

array_1=("Mike" "George" "Sam" "1234" "5678")
array_2=("Albert" "Isabel" "Sami" "4567" "9821")
array_3=("Michel" "Tom" "Cathy" "321" "5664")
array_4=("name 1" "name 2" "name 3" "1233" "4567")
array_5=...

To get single array elements (this is needed because not all are used in the script):

name1="${array_1[0]}"
name2="${array_1[1]}"
name3="${array_1[2]}"
number1="${array_1[3]}"
number2="${array_1[4]}"

Sometimes I want to use array_2 (or 3/4..) instead of array_1. To avoid replacing (array_1) in all the lines of the names and numbers, I'm looking to use a simple variable substitution, so tried to replace with different kind of quotes, including:

myarray="array_1" // also tried 'array_1' and $array_1
name1="${myarray[0]}" // also tried "${$!myarray[0]}" and different quotes combinations

At this point I'm a bit confused about how bash quotes and probably indirects may work for this example, none the found answers nor various tries worked so far, aiming to see if there is rather a simple approach to address this or should the way of how arrays are being used here needs to be changed. Any hint is appreciated.

Upvotes: 0

Views: 552

Answers (4)

Mark Reed
Mark Reed

Reputation: 95252

You need to make myarray a nameref with declare -n.

declare -n myarray=array_1

Then you reference it as if it were the named array:

$ echo "${myarray[0]}"
Mike

Note that this only works in bash 4.3+, however. Apple is allergic to GPL v3+ so macOS ships with 3.2 in /bin; if you're on a Mac, you'll need to install a newer version (e.g. with MacPorts or Homebrew).

Upvotes: 5

Shakiba Moshiri
Shakiba Moshiri

Reputation: 23794

You kind of need, an array of array which does not supported in but it does not mean you cannot make it

Here is a dirty way of having an array of array with quick access

script

#!/bin/bash

# bash strict mode
set -C
set -Ee
set -T
set -u
set -o pipefail

# global array
declare -a arr=();

# get each line as an array, start from 0
function array_of_array(){
    # get the index
    declare -r index=${1:?'Error: first arg is needed'};

# each line is an array
# delimiter is comma ,
data="name surname 11, name surname 12, 123, 456
name surname 21, name surname 22, 123, 456, 789
name surname 31, name surname 32, 123, 456";

    # extract that line, start from 0
    mapfile -s $index  -t array <<< "$data";

    # delimiter is ,
    IFS=',';

    # remove space after comma
    array=${array//, /,}

    # save it in arr, a global variable
    read -a arr <<< "${array[0]}";
}


# read first line into an array
# read -a arr  <<< "$(array_of_array 0)"
array_of_array 0
echo
echo '### first ###'
echo arr: "${arr[0]}"
echo arr: "${arr[1]}"
echo arr: "${arr[2]}"
echo arr: "${arr[3]}"
echo size: "${#arr[@]}"


# read second line into an array
# read -a arr <<< "$(array_of_array 1)"
array_of_array 1
echo
echo '### second ###'
echo arr: "${arr[0]}"
echo arr: "${arr[1]}"
echo arr: "${arr[2]}"
echo arr: "${arr[3]}"
echo arr: "${arr[4]}"
echo size: "${#arr[@]}"


sample output


### first ###
arr: name surname 11
arr: name surname 12
arr: 123
arr: 456
size: 4

### second ###
arr: name surname 21
arr: name surname 22
arr: 123
arr: 456
arr: 789
size: 5

Upvotes: 0

Renaud Pacalet
Renaud Pacalet

Reputation: 29040

If your bash is too old for namerefs you can use indirection:

array=array_1
name1="${!array[0]}"
name2="${!array[1]}"
name3="${!array[2]}"
number1="${!array[3]}"
number2="${!array[4]}"

Demo:

$ array=array_1
$ name1="${!array[0]}"
$ echo "$name1"
Mike
$ array=array_2
$ name1="${!array[0]}"
$ echo "$name1"
Albert

Upvotes: 2

murugesan openssl
murugesan openssl

Reputation: 207

@Mike

Proceed as per comment from Mark Reed.
I thought of sharing:
    $ cat "73180037.sh"
    #!/bin/bash
    array_1=("Mike" "George" "Sam" "1234" "5678")
    array_2=("Albert" "Isabel" "Sami" "4567" "9821")
    array_3=("Michel" "Tom" "Cathy" "321" "5664")
    array_4=("name 1" "name 2" "name 3" "1233" "4567")
    array_5=...
    for i in {1..5}
    do
        name1=array_$i[0];
        name2=array_$i[1];
        name3=array_$i[2];
        number1=array_$i[3];
        number2=array_$i[4];
        echo ${!name1} ${!name2} ${!name3} ${!name3} ${!number1} ${!number2}
    done

Upvotes: 0

Related Questions