3

I have a Bash script that I can't figure out how to quote a variable in. Any help would be greatly appreciated.

This code works perfectly:

myfunction() {
    for i in "${BASE_ARRAY[@]}"
    do

I want to pass the name of my array as a variable to the function so I can reuse it with other arrays. This is the code I am trying that fails:

myfunction() {
    for i in "${$1[@]}"
    do

Then I pass the following to the function:

myfunction BASE_ARRAY
codeforester
  • 39,467
  • 16
  • 112
  • 140
steveH
  • 155
  • 2
  • 9

2 Answers2

8

I've never had success passing arrays into functions.

For me, the two options are always to pass content into a function, or (since bash 4.3) pass in an array name which will be accessed using a reference. Consider the following example.

#!/usr/bin/env bash

myfunc() {
        local -n arr=$1
        printf '%s\n' "${arr[1]}"
        arr[1]=HELLO
}

a=(one two three)

myfunc a
printf '%s\n' "${a[1]}"

which produces:

$ ./sample
two
HELLO

Note that local -n is like declare -n in that it doesn't provide a local copy of the array, but rather a local pointer to the original content. In this example, if you change $arr[], you are actually changing the original array, $a[].

The traditional method of passing array content to a function has been described so many times here on StackOverflow that it hardly bears mentioning; you'll have no difficulty finding examples.

ghoti
  • 45,319
  • 8
  • 65
  • 104
  • This is awesome. I had no idea. Thanks for expanding my brain again. – Graham Jan 19 '17 at 01:29
  • 2
    This is very nice and, dare I say, exciting (at least as much as shell syntax can be). But it is also very new. I have a fully patched CenOS 7 system, and bash is still at version 4.2.26. For use in widely deployed scripts on random systems, I am afraid we will have to wait a good while. – Fred Jan 19 '17 at 01:57
  • 1
    This seems really similar to Fred's answer. Is there any benefit to adding the -n to the local variable? Is it faster? If I understand correctly, using the -n will allow me to make changes to the actual array from within the function? – steveH Jan 19 '17 at 18:25
5

Try this:

myfunction() {
    local x="$1[@]"
    for i in "${!x}"
    do

Indirect references in Bash look like "${!VARIABLE_CONTAINING_NAME_TO_EXPAND}". It is straightforward for variables that are not arrays.

But when you need to access an item in an array (or all items like in your case), you need to put the whole reference in the variable to be expanded.

Fred
  • 6,590
  • 9
  • 20
  • What does `$1[@]` expand into? That doesn't make sense to me. The positional parameters would be `$@`, and if you wanted to look at the array elements of an array named by `$1`, it seems to me you'd need to `eval` it. – Graham Jan 19 '17 at 01:27
  • Suppose $1 (the first positional argument) contains ARRAY_NAME. Then $1[@] will expand to ARRAY_NAME[@]. It is the ${!x} step that will execute the actual retrieval of the array element. – Fred Jan 19 '17 at 01:49
  • 1
    It might be clearer to write it as `local x="${1}[@]"` (though the original code is fully equivalent). – Gordon Davisson Jan 19 '17 at 02:06