8

Here is my bash case:

First case, this is what I want to do "aliasing" var with myvarA:

myvarA="variableA" varname="A" eval varAlias=\$"myvar"$varname echo $varAlias 

Second case for array variable and looping its members, which is trivial:

myvarA=( "variableA1" "variableA2" ) for varItem in ${myvarA[@]} do echo $varItem done 

Now somehow I need to use "aliasing" technique like example 1, but this time for array variable:

eval varAlias=\$"myvar"$varname for varItem in ${varAlias[@]} do echo $varItem done 

But for last case, only first member of myvarA is printed, which is eval evaluate to value of the variable, how should I do var array variable so eval is evaluate to the name of array variable not the value of the variable.

1
  • I think what I meant by "aliasing" is should be "indirection" in bash
    – uray
    CommentedSep 2, 2010 at 22:17

6 Answers 6

9

The simplest form for parameter expansion is: ${parameter}.
Using braces in confused case is better way.

Considering of possibilities of being included spaces in array of "myvarA", I think this would be the answer.

#!/bin/bash -x myvarA=( "variable A1" "variable A2" ) varname="A" eval varAlias=( '"${myvar'${varname}'[@]}"' ) eval varAlias=( \"\${myvar${varname}[@]}\" ) # both works for varItem in "${varAlias[@]}" # double quote and `@' is needed do echo "$varItem" done 
    2

    In your answer, varAlias isn't an array, so you can do for varItem in $varAlias which is just doing word splitting. Because of that if any of your original array elements include spaces, they will be treated as separate words.

    You can do scalar indirection like this: a=42; b=a; echo ${!b}.

    You can do indirection to an array of scalars like this:

    $ j=42; k=55; m=99 $ a=(j k m) $ echo ${!a[1]} 55 

    Unfortunately, there's no satisfactory way to do the type of array indirection you're trying to do. You should be able to rework your code so that no indirection is needed.

    See also BashFAQ/006.

      2

      I solved it; last example should be like this:

      eval varAlias=\${"myvar"$varname[@]} for varItem in ${varAlias[@]} do echo $varItem done 
        1

        It looks like you're trying to indirectly reference an array from the index of another.

        You might like to do something like:

        arr_one[0]=arr_two[@] 

        From there you can do:

        cmd "${!arr_one[0]}" 

        ...to indirectly reference a full expansion of "${arr_two[@]}". As near as I can tell, there is no direct method of indexing further. For example "${!arr_one[0][1]}" doesn't work as I'd hope (at least, not in bash) but you can do "${!arr_one[0]1:1}" and similar to slice the expansion as you could any other array. The end result is something like the 2-dimensional array structure that some other, more capable shells offer.

          0

          Just to note that that above accepted answer is not complete. To do an actual array assignment you are missing parenthesis around your original array otherwise you will still get a new array of size 1

          What i mean is that the following:

          eval varAlias=\${"myvar"$varname[@]} 

          should be changed to:

          eval varAlias=(\${"myvar"$varname[@]}) 

          You can validate this by taking both cases and running:

          echo ${#varAlias[@]} 

          In the original case you will get 1 in parenthesis you will get the actual number or elements in the original array. In both cases we basically create a new array.

            0

            This is how you would create a dynamically named variable (bash version < 4.3).

            # Dynamically named array my_variable_name="dyn_arr_names" eval $my_variable_name=\(\) # Adding by index to the array eg. dyn_arr_names[0]="bob" eval $my_variable_name[0]="bob" # Adding by pushing onto the array eg. dyn_arr_names+=(robert) eval $my_variable_name+=\(robert\) # Print value stored at index indirect echo ${!my_variable_name[0]} # Print value stored at index eval echo \${$my_variable_name[0]} # Get item count eval echo \${#$my_variable_name[@]} 

            Below is a group of functions that can be used to manage dynamically named arrays (bash version < 4.3).

            # Dynamically create an array by name function arr() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } # The following line can be replaced with 'declare -ag $1=\(\)' # Note: For some reason when using 'declare -ag $1' without the parentheses will make 'declare -p' fail eval $1=\(\) } # Insert incrementing by incrementing index eg. array+=(data) function arr_insert() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } eval $1[\$\(\(\${#${1}[@]}\)\)]=\$2 } # Update an index by position function arr_set() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } eval ${1}[${2}]=\${3} } # Get the array content ${array[@]} function arr_get() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } eval echo \${${1}[@]} } # Get the value stored at a specific index eg. ${array[0]} function arr_at() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; } local v=$1 local i=$2 local max=$(eval echo \${\#${1}[@]}) # Array has items and index is in range if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]] then eval echo \${$v[$i]} fi } # Get the value stored at a specific index eg. ${array[0]} function arr_count() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } local v=${1} eval echo \${\#${1}[@]} } array_names=(bob jane dick) for name in "${array_names[@]}" do arr dyn_$name done echo "Arrays Created" declare -a | grep "a dyn_" # Insert three items per array for name in "${array_names[@]}" do echo "Inserting dyn_$name abc" arr_insert dyn_$name "abc" echo "Inserting dyn_$name def" arr_insert dyn_$name "def" echo "Inserting dyn_$name ghi" arr_insert dyn_$name "ghi" done for name in "${array_names[@]}" do echo "Setting dyn_$name[0]=first" arr_set dyn_$name 0 "first" echo "Setting dyn_$name[2]=third" arr_set dyn_$name 2 "third" done declare -a | grep "a dyn_" for name in "${array_names[@]}" do arr_get dyn_$name done for name in "${array_names[@]}" do echo "Dumping dyn_$name by index" # Print by index for (( i=0 ; i < $(arr_count dyn_$name) ; i++ )) do echo "dyn_$name[$i]: $(arr_at dyn_$name $i)" done done for name in "${array_names[@]}" do echo "Dumping dyn_$name" for n in $(arr_get dyn_$name) do echo $n done done 

            Below is a group of functions that can be used to manage dynamically named arrays (bash version >= 4.3).

            # Dynamically create an array by name function arr() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -g -a $1=\(\) } # Insert incrementing by incrementing index eg. array+=(data) function arr_insert() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } declare -n r=$1 r[${#r[@]}]=$2 } # Update an index by position function arr_set() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } declare -n r=$1 r[$2]=$3 } # Get the array content ${array[@]} function arr_get() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } declare -n r=$1 echo ${r[@]} } # Get the value stored at a specific index eg. ${array[0]} function arr_at() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable" 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } [[ ! "$2" =~ ^(0|[-]?[1-9]+[0-9]*)$ ]] && { echo "Array index must be a number" 1>&2 ; return 1 ; } declare -n r=$1 local max=${#r[@]} # Array has items and index is in range if [[ $max -gt 0 && $i -ge 0 && $i -lt $max ]] then echo ${r[$2]} fi } # Get the value stored at a specific index eg. ${array[0]} function arr_count() { [[ ! "$1" =~ ^[a-zA-Z_]+[a-zA-Z0-9_]*$ ]] && { echo "Invalid bash variable " 1>&2 ; return 1 ; } declare -p "$1" > /dev/null 2>&1 [[ $? -eq 1 ]] && { echo "Bash variable [${1}] doesn't exist" 1>&2 ; return 1 ; } declare -n r=$1 echo ${#r[@]} } array_names=(bob jane dick) for name in "${array_names[@]}" do arr dyn_$name done echo "Arrays Created" declare -a | grep "a dyn_" # Insert three items per array for name in "${array_names[@]}" do echo "Inserting dyn_$name abc" arr_insert dyn_$name "abc" echo "Inserting dyn_$name def" arr_insert dyn_$name "def" echo "Inserting dyn_$name ghi" arr_insert dyn_$name "ghi" done for name in "${array_names[@]}" do echo "Setting dyn_$name[0]=first" arr_set dyn_$name 0 "first" echo "Setting dyn_$name[2]=third" arr_set dyn_$name 2 "third" done declare -a | grep 'a dyn_' for name in "${array_names[@]}" do arr_get dyn_$name done for name in "${array_names[@]}" do echo "Dumping dyn_$name by index" # Print by index for (( i=0 ; i < $(arr_count dyn_$name) ; i++ )) do echo "dyn_$name[$i]: $(arr_at dyn_$name $i)" done done for name in "${array_names[@]}" do echo "Dumping dyn_$name" for n in $(arr_get dyn_$name) do echo $n done done 

            For more details on these examples visit Getting Bashed by Dynamic Arrays by Ludvik Jerabek

              You must log in to answer this question.

              Start asking to get answers

              Find the answer to your question by asking.

              Ask question

              Explore related questions

              See similar questions with these tags.