How can I pass an array as parameter to a bash function?
Note: After not finding an answer here on Stack Overflow, I posted my somewhat crude solution myself. It allows for only one array being passed, and it being the last element of the parameter list. Actually, it is not passing the array at all, but a list of its elements, which are re-assembled into an array by called_function(), but it worked for me. If someone knows a better way, feel free to add it here.
Note: This is the somewhat crude solution I posted myself, after not finding an answer here on Stack Overflow. It allows for only one array being passed, and it being the last element of the parameter list. Actually, it is not passing the array at all, but a list of its elements, which are re-assembled into an array by called_function(), but it worked for me. Somewhat later Ken posted his solution, but I kept mine here for "historic" reference.
Improved by TheBonsai, thanks.
Example
With a few tricks you can actually pass named parameters to functions, along with arrays.
The method I developed allows you to access parameters passed to a function like this:
In other words, not only you can call your parameters by their names (which makes up for a more readable core), you can actually pass arrays (and references to variables - this feature works only in bash 4.3 though)! Plus, the mapped variables are all in the local scope, just as $1 (and others).
The code that makes this work is pretty light and works both in bash 3 and bash 4 (these are the only versions I've tested it with). If you're interested in more tricks like this that make developing with bash much nicer and easier, you can take a look at my Bash Infinity Framework, the code below was developed for that purpose.
DevSolar's answer has one point I don't understand (maybe he has a specific reason to do so, but I can't think of one): He sets the array from the positional parameters element by element, iterative.
An easier approuch would be
Requirement: Function to find a string in an array.
This is a slight simplification of DevSolar's solution in that it uses the arguments passed rather than copying them.
Commenting on Ken Bertelson solution and answering Jan Hettich:
How it works
the
takes_ary_as_arg descTable[@] optsTable[@]
line intry_with_local_arys()
function sends:descTable
andoptsTable
arrays which are accessible to thetakes_ary_as_arg
function.takes_ary_as_arg()
function receivesdescTable[@]
andoptsTable[@]
as strings, that means$1 == descTable[@]
and$2 == optsTable[@]
.in the beginning of
takes_ary_as_arg()
function it uses${!parameter}
syntax, which is called indirect reference or sometimes double referenced, this means that instead of using$1
's value, we use the value of the expanded value of$1
, example:likewise for
$2
.argAry1=("${!1}")
createsargAry1
as an array (the brackets following=
) with the expandeddescTable[@]
, just like writing thereargAry1=("${descTable[@]}")
directly. thedeclare
there is not required.N.B.: It is worth mentioning that array initialization using this bracket form initializes the new array according to the
IFS
or Internal Field Separator which is by default tab, newline and space. in that case, since it used[@]
notation each element is seen by itself as if he was quoted (contrary to[*]
).My reservation with it
In
BASH
, local variable scope is the current function and every child function called from it, this translates to the fact thattakes_ary_as_arg()
function "sees" thosedescTable[@]
andoptsTable[@]
arrays, thus it is working (see above explanation).Being that case, why not directly look at those variables themselves? It is just like writing there:
See above explanation, which just copies
descTable[@]
array's values according to the currentIFS
.In summary
I also want to emphasize Dennis Williamson comment above: sparse arrays (arrays without all the keys defines - with "holes" in them) will not work as expected - we would loose the keys and "condense" the array.
That being said, I do see the value for generalization, functions thus can get the arrays (or copies) without knowing the names:
for real copies: we can use an eval for the keys, for example:
and then a loop using them to create a copy. Note: here
!
is not used it's previous indirect/double evaluation, but rather in array context it returns the array indices (keys).descTable
andoptsTable
strings (without[@]
), we could use the array itself (as in by reference) witheval
. for a generic function that accepts arrays.