0

I have an unknown number of variable names with the pattern rundate*. For example, rundate=180618 && rundate2=180820. I know from here that I can send multiple variable names to a third variable: alld=(`echo "${!rundate*}"`) and while attempting to solve my problem, I figured out how to send multiple variable indices to a third variable: alld_indices=(`echo "${!alld[@]}"`). But, how do I send multiple values to my third variable: alld_values such that echo ${alld_values[@]} gives 180618 180820. I know from here how I can get the first value: firstd_value=(`echo "${!alld}"`). I suspect, I've seen the answer already in my searching but did not realize it. Happy to delete my question if that is the case. Thanks!

2 Answers2

2
#!/usr/bin/env bash

# set up some test data
rundate="180618"
rundate1="180820"
rundate2="Values With Spaces Work Too"

# If we know all values are numeric, we can use a regular indexed array
# otherwise, the below would need to be ''declare -A alld=( )''
alld=( )                       # initialize an array
for v in "${!rundate@}"; do    # using @ instead of * avoids IFS-related bugs
  alld[${v#rundate}]=${!v}     # populate the array, using varname w/o prefix as key
done

# print our results
printf 'Full array definition:\n   '
declare -p alld                 # emits code that, if run, will redefine the array
echo; echo "Indexes only:"
printf ' - %s\n' "${!alld[@]}"  # "${!varname[@]}" expands to the list of keys
echo; echo "Values only:"
printf ' - %s\n' "${alld[@]}"   # "${varname[@]}" expands to the list of values

...properly emits as output:

Full array definition:
   declare -a alld=([0]="180618" [1]="180820" [2]="Values With Spaces Work Too")

Indexes only:
 - 0
 - 1
 - 2

Values only:
 - 180618
 - 180820
 - Values With Spaces Work Too

...as you can see running at https://ideone.com/yjSD1J

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • something maybe wrong with the associative array suggestion. I was trying to validate with `rundate="180618" && rundate1="180820" && declare -A alld=( ) && for v in "${!rundate@}"; do alld[${v#rundate}]=${!v}; done` but got -bash: alld[${v#rundate}]: bad array subscript – Aaron Dickey May 02 '19 at 20:56
  • 1
    Right, that's because an empty string isn't a valid key. If you're going the associative route, just make it `$v`, not `${v#rundate}`. There's a reason I only put the `#rundate` back in when changing the code to use an indexed array (in which the empty string evaluates to `0`) instead of an associative one (in which it's invalid). – Charles Duffy May 02 '19 at 20:58
1

eval in a loop will do it.

$: for v in ${!rundate*}
>  do eval "alld_values+=( \$$v )"
>  done
$: echo "${alld_values[@]}"
180618 180820

or

$: eval "alld_values=( $( sed 's/ / $/g' <<< " ${!rundate*}" ) )"

or

$: echo "alld_values=( $( sed 's/ / $/g' <<< " ${!rundate*}" ) )" > tmp && . tmp
Paul Hodges
  • 13,382
  • 1
  • 17
  • 36
  • 1
    [BashPitfalls #50](http://mywiki.wooledge.org/BashPitfalls#hosts.3D.28_.24.28aws_....29_.29) is pertinent. (Granted, the OP's original code runs afoul of that as well). – Charles Duffy May 02 '19 at 17:16
  • Agreed. In fact, the code kind of depends on the very features that open it up to that particular bug. MUCH better to refactor the original code NOT to use the individual variables at all. – Paul Hodges May 02 '19 at 17:21
  • I see you have accepted this solution, but I *strongly* suggest you consider refactoring to an associative array design like that suggested by Charles... – Paul Hodges May 02 '19 at 18:48
  • 1
    I accepted your solution(initially) because it was posted first and worked. However, my developing script contains Charles' design. I'm encouraged to know this is what you would suggest. – Aaron Dickey May 02 '19 at 19:27