toddeTV
toddeTV

Reputation: 1517

Passing an array directly to a function in Shell

is it possible to pass an array directly to a function in shell/bash, without saving it first to a variable?

currently example:

function checkParameter(){
    param1=("${!1}")
    for a in "${param1[@]}"; do
        echo "${a}"
    done

    param2=("${!2}")
    for b in "${param2[@]}"; do
        echo "${b}"
    done
}

a=( "child 1 from 1" "child 2 from 1" "child 3 from 1" )
b=( "child 1 from 2" "child 2 from 2")
checkParameter a[@] b[@]

So can I pass the ( "child 1 from 1" "child 2 from 1" "child 3 from 1" ) and the ( "child 1 from 2" "child 2 from 2") somehow directly to the function checkParameter, without saving it in a and b first?

greetings and thanks,
christopher2007

Upvotes: 1

Views: 103

Answers (3)

mklement0
mklement0

Reputation: 437111

Generally, you cannot pass arrays to Bash scripts or functions as arrays:

When you pass an array on the command line, e.g., "${ary[@]}", you're not passing an array, but its elements as individual parameters; the first array element is bound to special parameter $1, the second to $2, ...

Your solution attempt employs a clever workaround by passing the name of array variables to the function, where variable indirection (${!...}) is used to access the array inside the function.[1]

By definition, this approach requires the arrays to be stored in variables up front.

As for your desire to do it without storing your arrays in a variable: You cannot pass array literals as arguments in Bash; the conceptual equivalent of that is to simply pass individual parameters.

The problem with that is that you won't be able to tell where the elements of one array end and the next one begins.

You can address that by introducing a separator parameter whose sole purpose is to indicate when an array ends.

For instance, if you know that your elements never contain a newline, you can use $\n as the separator:

#!/usr/bin/env bash

function checkParameter(){
  local -i arrayNdx=1
  for param; do # Loop over all parameters
    [[ $param == $'\n' ]] && { (( ++arrayNdx )); continue; }
    echo "From array $arrayNdx: [$param]"
  done  
}

# Pass the array elements as individual parameters
# and use $'\n' (a newline) to separate the elements of the 1st
# array from those of the 2nd.
checkParameter "a1-child 1" "a1-child 2" "a1-child 3" $'\n' "a2-child 1" "a2-child 2"

[1] Just to show a simplified version of your solution to make the variable-indirection part clearer:

function checkParameter(){
    for a in "${!1}"; do
        echo "${a}"
    done

    for b in "${!2}"; do
        echo "${b}"
    done
}

checkParameter a[@] b[@]

Upvotes: 0

Idriss Neumann
Idriss Neumann

Reputation: 3838

Are you sure that you need to use an array ?

checkparameters() {
    for param in "$@"; do
        echo "$param"
    done
}

checkparameters "a" "b" "c"

To answer the question, I don't think that is possible to pass an array as function's args without transformations.

EDIT

You could try something like :

[ ~]$ cat test.sh 
#!/bin/bash 

declare -a a1
a1=("a" "b")

declare -a a2
a2=("c" "d")

checkParameters(){
    for i in "$@"; do
        echo "Content of $i :"
        for j in $(eval "echo \${$(echo $i)[@]}"); do
            echo $j
        done
    done
}

checkParameters "a1" "a2"
[ ~]$ ./test.sh 
Content of a1 :
a
b
Content of a2 :
c
d

Upvotes: 0

user4832408
user4832408

Reputation:

"$1" is immutable. That is why your example has to store the value of it in a temporary variable. This holds true for $@ regardless of whether they are passed as an array or not.

Upvotes: 1

Related Questions