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:
callin
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
).