80
votes

As we know, in bash programming the way to pass arguments is $1, ..., $N. However, I found it not easy to pass an array as an argument to a function which receives more than one argument. Here is one example:

f(){
 x=($1)
 y=$2

 for i in "${x[@]}"
 do
  echo $i
 done
 ....
}

a=("jfaldsj jflajds" "LAST")
b=NOEFLDJF

f "${a[@]}" $b
f "${a[*]}" $b

As described, function freceives two arguments: the first is assigned to x which is an array, the second to y.

f can be called in two ways. The first way use the "${a[@]}" as the first argument, and the result is:

jfaldsj 
jflajds

The second way use the "${a[*]}" as the first argument, and the result is:

jfaldsj 
jflajds 
LAST

Neither result is as I wished. So, is there anyone having any idea about how to pass array between functions correctly?

5
possible duplicate of Passing arrays as parameters in bashchepner
@chepner thanks for reminding. I will check it later for some ideasRed Lv

5 Answers

97
votes

You cannot pass an array, you can only pass its elements (i.e. the expanded array).

#!/bin/bash
function f() {
    a=("$@")
    ((last_idx=${#a[@]} - 1))
    b=${a[last_idx]}
    unset a[last_idx]

    for i in "${a[@]}" ; do
        echo "$i"
    done
    echo "b: $b"
}

x=("one two" "LAST")
b='even more'

f "${x[@]}" "$b"
echo ===============
f "${x[*]}" "$b"

The other possibility would be to pass the array by name:

#!/bin/bash
function f() {
    name=$1[@]
    b=$2
    a=("${!name}")

    for i in "${a[@]}" ; do
        echo "$i"
    done
    echo "b: $b"
}

x=("one two" "LAST")
b='even more'

f x "$b"
49
votes

You can pass an array by name reference to a function in bash (since version 4.3+), by setting the -n attribute:

show_value () # array index
{
    local -n myarray=$1
    local idx=$2
    echo "${myarray[$idx]}"
}

This works for indexed arrays:

$ shadock=(ga bu zo meu)
$ show_value shadock 2
zo

It also works for associative arrays:

$ declare -A days=([monday]=eggs [tuesday]=bread [sunday]=jam)
$ show_value days sunday
jam

See also nameref or declare -n in the man page.

12
votes

You could pass the "scalar" value first. That would simplify things:

f(){
  b=$1
  shift
  a=("$@")

  for i in "${a[@]}"
  do
    echo $i
  done
  ....
}

a=("jfaldsj jflajds" "LAST")
b=NOEFLDJF

f "$b" "${a[@]}"

At this point, you might as well use the array-ish positional params directly

f(){
  b=$1
  shift

  for i in "$@"   # or simply "for i; do"
  do
    echo $i
  done
  ....
}

f "$b" "${a[@]}"
3
votes

This will solve the issue of passing array to function:

#!/bin/bash

foo() {
    string=$1
    array=($@)
    echo "array is ${array[@]}"
    echo "array is ${array[1]}"
    return
}
array=( one two three )
foo ${array[@]}
colors=( red green blue )
foo ${colors[@]}
0
votes

Pass the array as a function

array() {
    echo "apple pear"
}

printArray() {
    local argArray="${1}"
    local array=($($argArray)) # where the magic happens. careful of the surrounding brackets.
    for arrElement in "${array[@]}"; do
        echo "${arrElement}"
    done

}

printArray array