2

I have successfully been able to call a single array as a parameter, but I am having trouble passing through multiple arrays. Here is what I have so far:

calling function {
    array1=(1, 2, 3, 4)
    array2=(a, b, c, d)
    array3=(!, @, #, $)

    called function() "${array1[@]" "${array2[@]}" "${array3[@]}"
}

called function {
    local_array1=("${@}")      # i am guessing my problem lies here?
    local_array2=("${@}")      
    local_array3=("${@}")

    echo ${local_array1[@]}
    echo ${local_array2[@]}
    echo ${local_array3[@]}
}

2 Answers 2

7

A function or program's argument list is a single, long array. When you concatenate three different source arrays onto it, the result is still only one argument list, with the contents of those three arrays one after the other.

There are two solutions. The safest one is to concatenate onto a single argument list and pass arguments by value, with each array prefixed by its length:

caller() {
    array1=(1   2   3   4)
    array2=(a   b   c   d)
    array3=('!' '@' '#' '$')

    callee \
      "${#array1[@]}" "${array1[@]}" \
      "${#array2[@]}" "${array2[@]}" \
      "${#array3[@]}" "${array3[@]}"
}

callee() {
    # using declare -a makes the values truly local
    # without local or declare they're actually global
    declare -a local_array1=( "${@:1:$1}" ); shift "$(( $1 + 1 ))"
    declare -a local_array2=( "${@:1:$1}" ); shift "$(( $1 + 1 ))"
    declare -a local_array3=( "${@:1:$1}" ); shift "$(( $1 + 1 ))"

    printf 'array1 entry: %q\n' "${local_array1[@]}"
    printf 'array2 entry: %q\n' "${local_array2[@]}"
    printf 'array3 entry: %q\n' "${local_array3[@]}"
}

The other approach is to pass by reference. If you have bash 4.3, you can use a new shell feature called namevars, first implemented by ksh explicitly for this purpose:

caller() {
    array1=(1   2   3   4)
    array2=(a   b   c   d)
    array3=('!' '@' '#' '$')

    callee array1 array2 array3
}

callee() {
    declare -n local_array1=$1
    declare -n local_array2=$2
    declare -n local_array3=$3

    printf 'array1 entry: %q\n' "${local_array1[@]}"
    printf 'array2 entry: %q\n' "${local_array2[@]}"
    printf 'array3 entry: %q\n' "${local_array3[@]}"
}

However, pass-by-reference is somewhat more fragile: It depends on variable scope being accessible everywhere relevant, and a callee can modify values of the arrays in the caller (indeed, when using the bash-4.3 namevar approach showing here, that behavior is automatic: Any change to local_array1 will also modify array1).

Sign up to request clarification or add additional context in comments.

3 Comments

Interesting what would be an option to pass an array of arrays...
bash doesn't support arrays of arrays; the closest you could do is an array of names of other arrays, which is what -- in the contest of the code above -- "$@" already is. Iterate over them and define them as namerefs and there were are -- basically just replacing the repeated lines in the above with a loop.
Thank you for helping out! On the first solution for some reason I needed to declare the local variables like so: declare -a local_array1=( "${@:2:$1}" ); shift "$(( $1 + 1 ))" declare -a local_array2=( "${@:2:$1}" ); shift "$(( $1 + 1 ))" declare -a local_array3=( "${@:2:$1}" ); shift "$(( $1 + 1 ))" for it to parse the arrays correctly.
1

Characters in the third array have special meaning, in bash, two first arrays could be passed & printed like this:

#!/bin/bash

called_function()
{
    local local_array1=$1[@]      # i am guessing my problem lies here?
    local local_array2=$2[@] 

    echo ${!local_array1}
    echo ${!local_array2}
}

calling_function() 
{
    array1=(1, 2, 3, 4)
    array2=(a, b, c, d)

    called_function array1 array2 #array3
}

calling_function

produced this:

./test.sh 
1, 2, 3, 4
a, b, c, d

1 Comment

Pass-by-reference? Definitely clever, but the readers should be aware of the semantic differences between that and the typical pass-by-value approach.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.