1

If we:

  1. Define an array; and then..
  2. Define a function; and want to..
  3. Call that array from inside the function..

We can. Like so:


Input:

myArray=('1' '2' '3' '4' '5')

myFunction () 
{ 
local -n myList="$1";
echo "${myList[@]}";
}

myFunction myArray

Output:

1 2 3 4 5

So, ${myArray[@]} becomes ${myList[@]}, within the scope of myFunction.

But this method only works as of bash version 4.3.x.

How did (and how can) we do this with older versions?

1 Answer 1

3

In older bashes, you need "variable indirection" (4th paragraph of Shell Parameter Expansion), which is really ugly for arrays:

myArray=('1' '2' '3' '4' '5')
myFunction() {
    local arr="${1}[@]"         # array expansion *as a string*
    local values=( "${!arr}" )  # actual array expansion
    echo "${values[@]}"
}
myFunction myArray
1 2 3 4 5

Note that this gives you a copy of the array. Any modifications you make in the function will not alter myArray in the outer scope:

myFunc2_old () {
    local arr="${1}[@]"
    local values=( "${!arr}" )  # here's the copy
    values[0]=foo
    declare -p values
}
myFunc2_old myArray; declare -p myArray
declare -a values=([0]="foo" [1]="2" [2]="3" [3]="4" [4]="5")
declare -a myArray=([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")

As opposed to namerefs

myFunc2_ref () {
    local -n arr=$1
    arr[0]=foo
    declare -p arr
}
myFunc2_ref myArray; declare -p myArray
declare -n arr="myArray"
declare -a myArray=([0]="foo" [1]="2" [2]="3" [3]="4" [4]="5")
4
  • Thanks, let me just wrap my mind around that for a minute.. Is it both local arr="${1}[@]" AND local values=( "${!arr}" )? Or just one or the other?
    – voices
    Commented Dec 7, 2018 at 3:01
  • You need both. The first statement sets arr="myArray[@]" -- that's just a string. Then ${!arr} becomes ${myArray[@]} with indirect expansion. Then with the parentheses and double quotes, you get the elements of the array, forming the copy. Commented Dec 7, 2018 at 3:21
  • This has the same issue when the original array also has the name arr. It creates a cyclic name resolution. I recommend to use something more complicated name like __array__. Also to mutate the original array, one can use eval command
    – SwiftMango
    Commented Jan 17, 2021 at 0:58
  • I've come to use the function name as the nameref variable prefix: __myFunc2_ref__arr -- very ugly but unique. Commented Jan 17, 2021 at 3:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .