Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define a local array in a bash function and access it outside that function

I am trying to define a local array in a bash function and access it outside that function.

I realise that BASH functions do not return values but I can assign the results of a calculation to a global value. I expected this code to echo the content of array[] to the screen. I'm not sure why its failing.

function returnarray
{
local array=(foo doo coo)
#echo "inside ${array[@]}"
}


targetvalue=$(returnarray)
echo ${targetvalue[@]}
like image 958
Dave Avatar asked Mar 14 '15 08:03

Dave


3 Answers

You have two options. The first one is what @choroba prescribes, and it's probably the best and simplest: don't define your array local.

returnarray() {
    array=(foo doo coo) # NOT local
}

# call your function
returnarray
# now the array is in array and you may copy it for later use as follows:
targetvalue=( "${array[@]}" )
# print it to check:
declare -p targetvalue

This is neat, simple, safe, completely avoids the use of subshells (so it's more efficient). It has one caveat, though: it won't work with sparse arrays (but this should be a minor detail). There's another tiny disadvantage: the array needs to be copied.


Another option is to pass a variable name to your function, and have the function generate the array directly. This uses namerefs and is only available since Bash 4.3 (but it's really good—use it if you can!):

generatearray() {
    # $1 is array name in which array is generated
    local -n array="$1" || return 1
    array=( foo doo coo )
}
# call function that constructs the array with the array name
generatearray targetvalue
# display it
declare -p targetvalue
like image 63
gniourf_gniourf Avatar answered Oct 01 '22 09:10

gniourf_gniourf


To make the variable accessible from outside, don't declare it local. Make it global.

like image 36
choroba Avatar answered Oct 01 '22 09:10

choroba


First, as you say, there are no return values of bash functions. So the only way to pass a local value is to echo it.

However, this would lead to your targetvalue having everything you echoed in index 0 if interpreted as an array. To tell bash to treat the parts as array parts, you have to surround them by parentheses - from the bash manual:

Arrays are assigned to using compound assignments of the form name=(value1 ... valuen), where each value is of the form [sub‐ script]=string.

#!/bin/bash

function returnarray
{
    local array=(foo doo coo)
    echo "${array[@]}"
}


targetvalue=($(returnarray))
echo ${targetvalue[@]}
echo ${targetvalue[1]}

However, all of this is really programming around how bash works. It will be better to define your arrays globally.

As the use of echo makes bash interpret the values, this only works, if the values of the array are not affected by bash, for example the values may not contain wildcards or spaces, wildcards would be expanded to matching files and spaces in a value would translate into multiple array values.

like image 43
nlu Avatar answered Oct 01 '22 08:10

nlu