Red Lv
Red Lv

Reputation: 1429

How to pass array as an argument to a function in Bash

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?

Upvotes: 119

Views: 123465

Answers (8)

Paula T
Paula T

Reputation: 1598

You can also create a json file with an array, and then parse that json file with jq

For example:

my-array.json:

{
  "array": ["item1","item2"]
}

script.sh:

ARRAY=$(jq -r '."array"' $1 | tr -d '[],"')

And then call the script like:

script.sh ./path-to-json/my-array.json

Upvotes: 0

Gabriel Staples
Gabriel Staples

Reputation: 52677

Here is an example where I receive 2 bash arrays into a function, as well as additional arguments after them. This pattern can be continued indefinitely for any number of bash arrays and any number of additional arguments, accommodating any input argument order, so long as the length of each bash array comes just before the elements of that array.

Function definition for print_two_arrays_plus_extra_args:

# Print all elements of a bash array.
# General form:
#       print_one_array array1
# Example usage:
#       print_one_array "${array1[@]}"
print_one_array() {
    for element in "$@"; do
        printf "    %s\n" "$element"
    done
}

# Print all elements of two bash arrays, plus two extra args at the end.
# General form (notice length MUST come before the array in order
# to be able to parse the args!):
#       print_two_arrays_plus_extra_args array1_len array1 array2_len array2 \
#       extra_arg1 extra_arg2
# Example usage:
#       print_two_arrays_plus_extra_args "${#array1[@]}" "${array1[@]}" \
#       "${#array2[@]}" "${array2[@]}" "hello" "world"
print_two_arrays_plus_extra_args() {
    i=1

    # Read array1_len into a variable
    array1_len="${@:$i:1}"
    ((i++))
    # Read array1 into a new array
    array1=("${@:$i:$array1_len}")
    ((i += $array1_len))

    # Read array2_len into a variable
    array2_len="${@:$i:1}"
    ((i++))
    # Read array2 into a new array
    array2=("${@:$i:$array2_len}")
    ((i += $array2_len))

    # You can now read the extra arguments all at once and gather them into a
    # new array like this:
    extra_args_array=("${@:$i}")

    # OR you can read the extra arguments individually into their own variables
    # one-by-one like this
    extra_arg1="${@:$i:1}"
    ((i++))
    extra_arg2="${@:$i:1}"
    ((i++))

    # Print the output
    echo "array1:"
    print_one_array "${array1[@]}"
    echo "array2:"
    print_one_array "${array2[@]}"
    echo "extra_arg1 = $extra_arg1"
    echo "extra_arg2 = $extra_arg2"
    echo "extra_args_array:"
    print_one_array "${extra_args_array[@]}"
}

Example usage:

array1=()
array1+=("one")
array1+=("two")
array1+=("three")

array2=("four" "five" "six" "seven" "eight")

echo "Printing array1 and array2 plus some extra args"
# Note that `"${#array1[@]}"` is the array length (number of elements
# in the array), and `"${array1[@]}"` is the array (all of the elements
# in the array) 
print_two_arrays_plus_extra_args "${#array1[@]}" "${array1[@]}" \
"${#array2[@]}" "${array2[@]}" "hello" "world"

Example Output:

Printing array1 and array2 plus some extra args
array1:
    one
    two
    three
array2:
    four
    five
    six
    seven
    eight
extra_arg1 = hello
extra_arg2 = world
extra_args_array:
    hello
    world

For further examples and detailed explanations of how this works, see my longer answer on this topic here: Passing arrays as parameters in bash

Upvotes: 0

andranikasl
andranikasl

Reputation: 1342

Try like this

function parseArray {
    array=("$@")

    for data in "${array[@]}"
    do
        echo ${data}
    done
}

array=("value" "value1")

parseArray "${array[@]}"

Upvotes: 4

AndrewD
AndrewD

Reputation: 5208

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

Upvotes: 0

Edouard Thiel
Edouard Thiel

Reputation: 6228

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.

Upvotes: 88

choroba
choroba

Reputation: 241868

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"

Upvotes: 136

Lavitha
Lavitha

Reputation: 51

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[@]}

Upvotes: 4

glenn jackman
glenn jackman

Reputation: 246807

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[@]}"

Upvotes: 22

Related Questions