Bruce
Bruce

Reputation: 29

How to nest variables and loop through sub-variables in bash

I am trying to write a script that generates csv files from mysql. The csv files from mysql is working fine, however, I'm struggling with a way to loop through variables, or treat them as an array to loop through.

Some example variables are below

c1="Client 1"
c1_s1_name=Alpha
c1_s1_id=761967
c1_s2_name=Beta
c1_s2_id=415612

c2="Client 2"
c2_s1_name=XYZ
c2_s1_id=438976
c2_s2_name=ABC
c2_s2_id=982012

c3="Client 3"
c3_s1_name=No-Name
c3_s1_id=347654
c3_s2_name=House
c3_s2_id=109321

I then have some quasi-code that attempts to run a sql script for each client as below but

# loop through all clients
for all_clients in $c1 $c2 $c3
do

# and then loop through for all survey names and all survey ids for each seperate client
for survey_name in $*_name and survey_id in $*_id
do
mysql -h "localhost" -u "root" "$DATABASE" -e "SELECT count(*) FROM $survey_id" | sed 's/\t/","/g;s/^/"/;s/$/"/;s/\n//g' > $all_clients-$survey_name-filename-count.csv
done

done

I'm not sure how to set the script up so that the c1 variables are run as a set and then c2, followed by c3. I'm guessing an array might be what I need but I'm not sure?

I've also come across the answer below but it's for PHP, even though it looks suspiciously like bash...

Group variables and loop through them

Upvotes: 1

Views: 54

Answers (1)

vdavid
vdavid

Reputation: 2544

You need to build the name of your dynamic variable and then dereference it with the {!var} syntax. Granted that you know your variable names in advance (i.e. the first part is always c1, c2 or c3, the second part is always s1 or s2, …), you can use something like that:

for x in c1 c2 c3; do
  for y in s1 s2; do
    for z in name id; do
      xyz=${x}_${y}_${z}
      # Use ${!xyz} to get the contents of the variable
    done
  done
done

Example (but without your mysql call, obviously)

I have used x, y and z to emphasize how the variable is constructed, but you can replace x by all_clients, etc..

You can use a slightly more advanced technique if the number of c* and s* is not known in advance.

numc=3
nums=2
for x in $(seq -f 'c%g' $numc); do
  for y in $(seq -f 's%g' $nums); do
    for z in name id; do
      xyz=${x}_${y}_${z}
      # Use ${!xyz} to get the contents of the variable
    done
  done
done

Example

The magic here is from seq. For example, in the following call:

seq -f 'c%g' $numc

The $numc option says you want to iterate from 1 to $numc. The -f 'c%g' option says that you want to form a printf-like string, in this case the letter c followed by the numeric value. So, the above example will write:

c1
c2
c3

The whole string is captured by $() which means the output will be inlined in your script. All in all, the following line:

for x in $(seq -f 'c%g' $numc); do

Will be interpreted as:

for x in c1 c2 c3; do

Which is equivalent to the initial for loop, except that now you control the number of iterations.

Upvotes: 1

Related Questions