Here is my attempt:

rand_var() {
printf "%s\n" "${${!1}[RANDOM % ${#${!1}[@]}]}"

And I run it like this

array=("something" "somethingelse" "test")
rand_var array

However, it tells me bad substitution. I think it may have something to do with the variables and quoting but I can't figure it out, I use ${!1} so that it acctually uses the contents of the variable and not just array. This line has worked before when I specify the variable name instead of ${!1}.

  • Related, maybe dupe: Indirect return of all elements in an array. The short version is that you can't use indirection that way and probably need eval. – Michael Homer Jan 8 '16 at 1:40
  • Why not just printf '%s\n' "${array[RANDOM%${#array[@]}]}" – cuonglm Jan 8 '16 at 1:49
  • 1
    Actually nm="$1[@]";tmp=("${!nm}");printf "%s\n" "${tmp[RANDOM % ${#tmp[@]}}" works without eval, but only by copying the array first. – Michael Homer Jan 8 '16 at 1:50
  • @cuonglm different variable names. – DisplayName Jan 8 '16 at 1:53

You can do what you want by copying the array into a local variable, and then selecting from that array:

rand_var() {
    local nm="$1[@]"
    local tmp=("${!nm}")
    printf "%s\n" "${tmp[RANDOM % ${#tmp[@]}]}"

I don't think you can do it otherwise, because you can't indirect to the length of the array. If you passed in the length to the function as well:

rand_var_len() {
    local nm="$1[$((RANDOM % $2))]"
    printf "%s\n" "${!nm}"
rand_var_len array ${#array[@]}

then you could do it without any copying.

To avoid both, you'll need to use one of the eval-alikes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.