1

I have a situation where I have large number of numbered variables. I want to evaluate each variable and set variable to a specific string if the condition is matched.

#!/bin/bash
var1=""
var2="1233123213"
var3="22332323222324242"
var4=""
var5=""

for i in 1 2 3 4 5
do 
   if [ -z "$var{$}i" ]
      then
          var{$}i="None"
   fi
echo "var{$}i \r"
done

but the problem is when I run the script I get following.

{1} \r
{2} \r
{3} \r
{4} \r
{5} \r

How I can fix this.

user2107349
  • 191
  • 2
  • 3
  • 16

3 Answers3

3

Use indirect variable expansion in bash with syntax {!var}.

From the man bash page,

If the first character of parameter is an exclamation point (!), a level of variable indirection is introduced. Bash uses the value of the variable formed from the rest of parameter as the name of the variable; this variable is then expanded and that value is used in the rest of the substitution, rather than the value of parameter itself. This is known as indirect expansion. The exclamation point must immediately follow the left brace in order to introduce indirection.

Modify your code to something like below,

for i in 1 2 3 4 5
do
     var="var$i"
     [ -z "${!var}" ] && declare "var$i"="none"
done

printf "var1=%s\n" "$var1"
printf "var2=%s\n" "$var2"
printf "var3=%s\n" "$var3"
printf "var4=%s\n" "$var4"
printf "var5=%s\n" "$var5"

The syntax "${!var}" in this case evaluates the value of the variable within the string var which is var1, var2, var3... and the declare syntax sets the variable value at run-time, only for those variables that are empty. Now on printing those variables produces,

var1=none
var2=1233123213
var3=22332323222324242
var4=none
var5=none
Inian
  • 80,270
  • 14
  • 142
  • 161
1

Indirect assignment will work here, but in this specific case arrays seem like a good fit :

#!/bin/bash
declare -a var=()
var+=("")
var+=(1233123213)
var+=(22332323222324242)
var+=("")
var+=("")

for i in "${!var[@]}"
do
  [[ "${var[$i]}" ]] || var[$i]="None"
  echo "Index: $i - Value: ${var[$i]}"
done
Fred
  • 6,590
  • 9
  • 20
  • Appreciate your logic here, but this is changing OP's requirement to use dynamic variable names. – Inian Feb 06 '17 at 11:50
  • This uses a numerical-indexed array, but you could use an associative array for more complex cases. Arrays are a form of indirect assignment that, when it works, is often going to be cleaner/safer than initializing many separate variables. – Fred Feb 06 '17 at 11:50
  • But I assume, if OP prefers a way, it is better to stick that way, than to deviate with other possible ways – Inian Feb 06 '17 at 11:51
  • 1
    @Inian Maybe the OP really wants/needs separate variables, maybe the OP simply does not know how to use arrays to achieve the desired result, in which case not answering the question exactly as asked might also be useful. – Fred Feb 06 '17 at 11:51
  • 1
    It is not _safe_ to assume OP doesn't know how to use arrays, it is good to recommend of safe alternate practices if their own logic will not help solve the problem. Who are we to decide if using dynamic variable assignment is only a small part of something _big_ OP is trying to do ! – Inian Feb 06 '17 at 11:56
  • @Inian We certainly do agree on this : it is not for us to decide what the proper solution is the for the person asking the question : in many cases there is more than one approach, and hence it is useful for the OP to have more than one answer in order to be able to pick the one that best suits their situation. Other readers may also appreciate having more than one approach presented, as that offers learning opportunities. – Fred Feb 06 '17 at 12:22
1

Consider using an array instead of numbered variables:

#!/bin/bash
var[1]=""
var[2]="1233123213"
var[3]="22332323222324242"
var[4]=""
var[5]=""

for i in 1 2 3 4 5
do 
   if [ -z "${var[i]}" ]
      then
          var[i]="None"
   fi
echo "${var[i]} \r"
done
MarcM
  • 2,173
  • 22
  • 32