Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Returning array from a Bash function

I am making a bash script and I have encountered a problem. So let's say I got this

function create_some_array(){
  for i in 0 1 2 3 .. 10
  do
    a[i]=$i
  done
}

create_some_array
echo ${a[*]}

Is there any way I can make this work? I have searched quite a lot and nothing I found worked. I think making the a[] a global variable should work but I can't find something that actually works in my code. Is there any way to return the array from the function to main program?

Thanks in advance

like image 548
KayKo Avatar asked Feb 12 '13 18:02

KayKo


People also ask

Can bash functions return values?

A bash function can return a value via its exit status after execution. By default, a function returns the exit code from the last executed command inside the function. It will stop the function execution once it is called. You can use the return builtin command to return an arbitrary number instead.

How do I print an array in bash?

Print Bash Array We can use the keyword 'declare' with a '-p' option to print all the elements of a Bash Array with all the indexes and details. The syntax to print the Bash Array can be defined as: declare -p ARRAY_NAME.

Can bash function return multiple values?

Example: Bash function returns multiple values, passed via command substitution, with a READ command and Here string in calling script #bash #bash_exemplar · GitHub.


3 Answers

This won't work as expected when there are whitespaces in the arrays:

function create_some_array() {
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]="$i $[$i*$i]"
    done
    echo ${a[@]}
}

and worse: if you try to get array indices from the outside "a", it turns out to be a scalar:

echo ${!a[@]}

even assignment as an array wont help, as possible quoting is naturally removed by the echo line and evaluation order cannot be manipulated to escape quoting: try

function create_some_array() {
...
    echo "${a[@]}"
}

a=($(create_some_array 0 10))
echo ${!a[@]}

Still, printf seems not to help either:

function create_some_array() {
...
    printf " \"%s\"" "${a[@]}"
}

seems to produce correct output on one hand:

$ create_some_array 0 3; echo
 "0 0" "1 1" "2 4" "3 9"

but assignment doesn't work on the other:

$ b=($(create_some_array 0 3))
$ echo ${!b[@]}
0 1 2 3 4 5 6 7

So my last trick was to do assignment as follows:

$ eval b=("$(create_some_array 0 3)")
$ echo -e "${!b[@]}\n${b[3]}"
0 1 2 3
3 9

Tataaa!

P.S.: printf "%q " "${a[@]}" also works fine...

like image 156
Hans Avatar answered Sep 28 '22 07:09

Hans


This works fine as described. The most likely reason it doesn't work in your actual code is because you happen to run it in a subshell:

cat textfile | create_some_array
echo ${a[*]}

would not work, because each element in a pipeline runs in a subshell, and

myvalue=$(create_some_array)
echo ${a[*]}

would not work, since command expansion happens in a subshell.

like image 33
that other guy Avatar answered Sep 28 '22 06:09

that other guy


You can make an array local to a function, and then return it:

function create_some_array(){
    local -a a=()
    for i in $(seq $1 $2); do
        a[i]=$i
    done
    echo ${a[@]}
}

declare -a a=()

a=$(create_some_array 0 10)

for i in ${a[@]}; do
   echo "i = " $i
done
like image 27
didierc Avatar answered Sep 28 '22 05:09

didierc