0

I need to call on an array in a bash script which name is defined by a string variable, like so:

var="array"
array=( 
1
2
3
)

$var will always equal the name of an array

#failed attempts at echoing ${array[@]}
echo "${!var}          # returns only the first value of the array

echo "${!var[@]}" # returns 0

tempvar='${'$var'[@]}' # makes a new variable with value of "${array[@]}" echo "${!tempvar}" #returns 'invalid variable name'

I'm new at this and don't see a way to figure this out. Thank you in advance.

  • 1
    Some unsolicited advice: if you find yourself writing code that needs this sort of feature, that's a very strong indication that you should probably be using a proper programming language and not a shell. – terdon Jun 21 '22 at 14:38

2 Answers2

0

Beware in bash (like in ksh whose array design bash copied), arrays are not like normal arrays but sparse arrays so more like associative arrays with keys limited to positive integers.

Here, you can do:

$ array=( [12]=a [23]=b [34]=c )
$ var=array
$ tempvar_for_separated_out_keys='!'$var[@]
$ tempvar_for_separated_out_values=$var[@]
$ printf -- '- <%s>\n' "${!tempvar_for_separated_out_keys}"
bash: !array[@]: invalid variable name
$ printf -- '- <%s>\n' "${!tempvar_for_separated_out_values}"
- <a>
- <b>
- <c>

(yes, the one for the keys doesn't work yet).

Or you could use a nameref instead (also from ksh though with some differences).

$ typeset -n var=array
$ printf -- '- <%s>\n' "${!var[@]}"
- <12>
- <23>
- <34>
$ printf -- '- <%s>\n' "${var[@]}"
- <a>
- <b>
- <c>

Or you could switch to zsh, where dereferencing is done with the P parameter expansion flag. zsh arrays are arrays, though it also has proper associative arrays with keys as arbitrary strings (of any byte or character).

$ array=( a b c '' ) var=array
$ printf -- '- <%s>\n' ${(P)var}
- <a>
- <b>
- <c>
$ printf -- '- <%s>\n' "${(P@)var}"
- <a>
- <b>
- <c>
- <>
$ typeset -A hash=( 12 a 23 b 34 c '' empty )
$ var=hash
$ printf -- '- <%s>\n' "${(Pk@)var}"
- <>
- <34>
- <23>
- <12>
$ printf -- '- <%s>\n' "${(Pv@)var}"
- <empty>
- <c>
- <b>
- <a>
$ printf -- '- <%s> -> <%s>\n' "${(Pkv@)var}"
- <> -> <empty>
- <34> -> <c>
- <23> -> <b>
- <12> -> <a>

(k flag for the keys, v flag for the values (default), @ flag inside quotes to preserve empty elements like for the Bourne shell's "$@").

0

bash specific

To make a reference to the array, use a "nameref" with declare -n

array=(1 2 3)
var=array

declare -n a=$var

for idx in "${!a[@]}"; do echo "$idx -> ${a[idx]}"; done a[4]="hello" declare -p a array # original altered by above assignment

outputs

0 -> 1
1 -> 2
2 -> 3
declare -n a="array"
declare -a array=([0]="1" [1]="2" [2]="3" [4]="hello")

To make a copy of the array, use an indirect variable: this is ugly

tmp=${var}[@]          # constructing a string
b=( "${!tmp}" )        # indirect variable expansion
b[4]="goodbye"

declare -p tmp b array # original not changed

outputs

declare -- tmp="array[@]"
declare -a b=([0]="1" [1]="2" [2]="3" [3]="hello" [4]="goodbye")
declare -a array=([0]="1" [1]="2" [2]="3" [4]="hello")

Notice how the index for the "hello" element changed in b: this is because the b=("${!tmp}") only made a copy of the array elements, not the indices.

glenn jackman
  • 85,964