NOTE: This answer uses eval
, and should be avoided where possible. See Freddy's answer, which uses declare -n
/ local -n
to create a named reference.
This approach may be necessary if you're using an old version of bash.
As already pointed out, you're passing the literal string arr
, and that isn't an array, hence the "bad substitution".
You can to use eval
to build a string that results in expanding to what you're after:
arr_to_file() {
local cmd
printf -v cmd 'local -a _content=( "${%q[@]}" )' "${1}"
eval "${cmd}"
printf '%s\n' "${_content[@]}" > "${2}"
}
mapfile -t arr < <(echo "one" ; echo "two" ; echo "three")
arr_to_file arr file
eval
usually gets a big warning notice, so here's yours: "eval is super dangerous if you don't trust the string you're giving it".
If we're very careful with eval
, then it can be used somewhat safely. Here printf "%q" "${1}"
is used to quote the first argument suitably for shell input (e.g: printf '%q' '}'
won't break out of the variable's name). Thanks to Charles Duffy for the revised and significantly safer and more readable snippet.
This approach will also work for associative arrays (i.e: arrays that use keys instead of indexes), but the output will be unordered.