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)?

1

4 Answers 4

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:

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...

2
  • I suspect I probably don't really need the inner eval, but I'm not interested in optimizing this.
    – Rich
    Mar 19, 2019 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. Mar 19, 2019 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.

5
  • Question explicitly states "without using arrays", and your bash solution makes an array.
    – Rich
    Mar 19, 2019 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. Mar 19, 2019 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, 2019 at 18:38
  • @Rich, no list holds the list of variable names, so we can loop over them later, not their values. Mar 19, 2019 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, 2019 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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .