0

My environment can have a flexible number of variables defined with the following format:

Var1Value=A
Var2Value=B
Var3Value=C

I now would like to iterate over the variables as long as they exists. In pseudo code:

i=1
while [exists "Var"$i"Value"]; do
 echo "found variable, now doing some more complex processing logic"
 #do some more stuff
 i=$((i + 1)) 
done

I do I make this work in bash (without using arrays)?

4 Answers4

5

Use a nameref. They work sort of like pointers to other variables (in Bash 4.3 and later):

Var1Value=A
Var2Value=B
Var3Value=C
Var4Value=""

for (( i=1 ; ; i++ )); do
    n="Var${i}Value"                # the name of var
    declare -n p="$n"               # reference to the var
    [ "${p+x}" ] || break           # see if it exists
    echo "$n: '$p'"
done

"${p+x}" evaluates to x if the variable pointed to by p exists, so this deals with set but empty variables, too.

Alternatively, use indirect variable expansion ${!n}, which refers to the variable named by n.

for (( i=1 ; ; i++ )); do
    n="Var${i}Value"                # the name of var
    [ "${!n+x}" ] || break          # see if it exists
    echo "$n: '${!n}'"
done

But really, you should use an array. None of the three choices here are standard, but arrays are by far the most logical.

VarValue=( A B C )

for value in "${VarValue[@]}"; do
    # use "$value" here
    printf 'Value is "%s"\n' "$value"
done

See also:

Kusalananda
  • 333,661
ilkkachu
  • 138,973
1

This seems to work:

for ((i=1;i<=3;i++)); do
    eval echo "$"$(eval echo Var${i}Value)
done

There's a joke in there somewhere about it being horribly eval...

Rich
  • 823
  • I suspect I probably don't really need the inner eval, but I'm not interested in optimizing this. – Rich Mar 19 '19 at 17:25
  • Thanks for the quick reply Rich. The echo statement is meant as a placeholder for some more complicated work, therefore I'd still need a conditional statement which is what I'm struggling with. I'll update the question to be more clear. – Bernie Lenz Mar 19 '19 at 17:28
1

To check if a variable is set, see How do I check if a variable exists in an 'if' statement? ([ -v "Var${i}Value" ] (ksh/zsh/bash) or eval "[ -n \"\${Var${i}Value+set}\" ]" (POSIX)).

Now, to loop over the variables whose name matches a pattern, in zsh, you could do:

for varname in ${(Mk)parameters:#Var<->Value}; do
  something with "$varname" and its value: "${(P)varname}"
done

To process them in numeric order, add the n parameter expansion flag (change Mk to Mkn).

With bash:

readarray -t list < <(compgen -v | grep -xE 'Var[[:digit:]]+Value')
for varname in "${list[@]}"; do
  something with "$varname" and its value: "${!varname}"
done

Or replacing the readarray with split+glob to avoid using an array:

IFS=$'\n' # split on newline
for varname in $(compgen -v | grep -xE 'Var[[:digit:]]+Value'); do
  something with "$varname" and its value: "${!varname}"
done

To process them in numeric order and assuming your sort is GNU sort, pipe the output of grep into sort -V.

  • Question explicitly states "without using arrays", and your bash solution makes an array. – Rich Mar 19 '19 at 18:35
  • @Rich, I interpret the without using arrays as meaning without replacing the varxvalue with varvalue[x]. I've added a split+glob variant that avoids the array variable. – Stéphane Chazelas Mar 19 '19 at 18:37
  • And that would be a highly accurate description of exactly what you're doing in your solution - aside from the fact you also changed the name from varvalue[x] to list[x]. – Rich Mar 19 '19 at 18:38
  • @Rich, no list holds the list of variable names, so we can loop over them later, not their values. – Stéphane Chazelas Mar 19 '19 at 18:49
  • I see you added a split+glob solution to your answer. Thank you for recognizing your error in working to the specification! – Rich Mar 19 '19 at 19:00
0

For loop can be used if variables are known:

Example:

#!/bin/bash

for i in var1 var2 var3
        do
           echo " This is $i"
           #More commands.
        done

output

 This is var1
 This is var2
 This is var3