0

In my script, I found some operations on an array are reusable. So I am considering to refactor the reusable code into a function or a script.

However how can I write a function or script so that I can provide an array as a positional parameter to a function or script? or achieve something similar?

Thanks.

Tim
  • 101,790

2 Answers2

3
my_func param1 param2 param2 after_this_the_array_values "${myarr[@]}"

my_func () {
    shift 4
    local array=("$@")
}
Tim
  • 101,790
Hauke Laging
  • 90,279
3

Using a name reference in a recent (>=4.3) version of bash:

foo () {
    local param1=$1
    local -n arr=$2

    printf 'array: %s\n' "${arr[@]}"
}

myarray=( some items go here )
foo something myarray

The name of the array variable is passed as the second parameter to the function. The function declares a name reference variable that receives this name. Any access to that name reference variable will access the variable whose name was passed to the function.

This obviously works with more than one array.

Note that in the example above, you can not pass a variable named arr to the function, so some care has to be taken to avoid name clashes (ksh93, which also supports name references, don't have this issue due to different scoping).


Note that this approach does not work when calling another shell script. When calling another shell script, the array has to be passed on the command line of that other script, which means it has to be passed as a set of strings. To pass a single array this way is relatively easy, and Hauke Laging shows the basics of how to do this in his answer.

If you have full control over the contents of the arrays, you may be able to encode their data as single strings, possibly by delimiting their elements using some delimiter and then parsing these strings in the target script to re-form the arrays. Another possibility would be to adopt a JSON "interface" between your scripts, meaning you would encode the data as JSON, pass it on the scripts standard input (or similar), and decode the document using jq. This does feel rather cumbersome though, and it would add a massive overhead.

Kusalananda
  • 333,661
  • Thanks. (1) If using a script instead of a function, what is your solution? (2) If I want to reuse the function in multiple scripts so need to wrap its definition into its own script, what should I do? Note that (1) and (2) are separate not combined. – Tim Jun 05 '18 at 17:46
  • @Tim (2) As discussed earlier, I would source the function's script file in the script that needs to use it. In this case, I would also slightly obfuscate the name reference variable name, maybe by prefixing its name with an underscore, just so that I was more sure that its name would not clash with the names of variables that I might call the function with. – Kusalananda Jun 05 '18 at 17:49
  • Thanks. (1) If using a script instead of creating any function, i.e. if foo is a script not a function, will reference still work? – Tim Jun 05 '18 at 17:51
  • @Tim (1) If I had to call a script with an array. I would use Hauke Laging's solution. A script would not be able to receive the array in the same way. – Kusalananda Jun 05 '18 at 17:51
  • Thanks. "in the example above, you can not pass a variable named arr to the function". Why can't an array outside a function have the same name as an array inside the function? Doesn't the one inside the function have a local scope, while the one outside has a global scope, so no conflict if they have the same name? – Tim Jun 08 '18 at 05:54
  • @Tim I ran into this in one of my own pieces of code, so I wrote a question about it a while back: https://unix.stackexchange.com/questions/302578/circular-name-references-in-bash-shell-function-but-not-in-ksh – Kusalananda Jun 08 '18 at 06:38