0

I'm attempting to write a function that writes arrays with a name that's passed in. Given the following bash function:

function writeToArray {
    local name="$1"
    echo "$name"
    declare -a "$name"
    ${name[0]}="does this work?"      
}

Running like this:

writeToArray $("test")

I get two errors:

bash: declare: `': not a valid identifier
=does this work?: command not found

I am expecting to be able to do this:

writeToArray $("test")
for item in "${test[@]}"; do
        echo "item"
        echo "$item"
done

This should print:

item
does this work?

How could I properly configure this to write the array (named test in the example, such that this array named test is readable outside the function)?

Lee
  • 471
  • 3
  • 5
  • 15
  • 1
    @EdMorton Updated, I'm aiming to create an array called "test" that contains the string "does this work?" as its first element. – Lee Mar 08 '23 at 15:44

1 Answers1

3

You'd use a nameref for that:

writeToArray() {
    local -n writeToArray_name="$1"
    writeToArray_name[0]="does this work?"      
}

Testing:

bash-5.0$ test[123]=qwe
bash-5.0$ writeToArray test
bash-5.0$ typeset -p test
declare -a test=([0]="does this work?" [123]="qwe")

With older versions of bash which didn't have namerefs yet, you could use eval:

writeToArray() {
  eval "$1[0]='does this work?'"
}

When writeToArray is invoked with test as argument, eval is passed test[0]='does this work?' as argument, and that in turns is evaluated as code in the shell language where it assigns does this work? to the element of index 0 of the test array (also works for associative array; scalar variables are converted to arrays).

Note that $("test") is syntax to capture and expand the output of test command and split+glob it when in list context. test (aka [) produces no output when not passed any argument), so $("test") expands to the empty string and split+glob gives you nothing at all out of it.

Here, it's the name of your variable that you want to pass to writeToArray, so test, not its contents ("$test") nor the output of a command by the same name ("$(test)") let alone the output of a command by the same name subject to split+glob as with your $("test") attempt.

ilkkachu
  • 133,243
  • 15
  • 236
  • 397
Stéphane Chazelas
  • 522,931
  • 91
  • 1,010
  • 1,501
  • Great answer, I'd become confused over use of `$(...)`. I also noted your answer worked for `writeToArray "test"` (with quotation marks). – Lee Mar 08 '23 at 16:06
  • 1
    @Lee, would also work with `"writeToArray" 'te'"st"`. Quotes in shells are to prevent some characters to be treated specially (and double quotes also prevent split+glob which is why you almost always want quotes around variable expansions), but here none of the characters in `writeToArray` or `test` are special to the shell so quoting is not needed. The only special characters are space (used to delimit arguments to that command) and newline used to delimit that command. – Stéphane Chazelas Mar 08 '23 at 16:11