Networking

Unix and Linux network configuration. Multiple network interfaces. Bridged NICs. High-availability network configurations.

Applications

Reviews of latest Unix and Linux software. Helpful tips for application support admins. Automating application support.

Data

Disk partitioning, filesystems, directories, and files. Volume management, logical volumes, HA filesystems. Backups and disaster recovery.

Monitoring

Distributed server monitoring. Server performance and capacity planning. Monitoring applications, network status and user activity.

Commands & Shells

Cool Unix shell commands and options. Command-line tools and application. Things every Unix sysadmin needs to know.

Home » Commands & Shells

Dynamic Variables in BASH

Submitted by on October 10, 2013 – 9:32 am

Assigning variables is easy if you know how many you have and what they are called. The value of a variable can be, well, variable. But the names and number of variables need to be known ahead of time. Or do they? I am not a big fan of using “expr” and “eval” in shell scripts, but sometimes there’s no other option.

Let’s say you need to assign variables var1 through var5. For example, here we set var1 through var5 to a random number between 1 and 100:

var1=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
var2=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
var3=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
var4=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
var5=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
echo "${var1}, ${var2}, ${var3}, ${var4}, ${var5}"
> 36, 16, 99, 3, 74

Now imagine you need to assign var1 through var100, or, worse yet, var1 through varN, where N is not know ahead of time and is determined dynamically during the script’s execution. This can be an annoying little problem.

In the following example, the N is determined as a random number between 1 and 100. In this case it happened to be 25. So we need to set var1 through varN to a random number between 1 and 100. And then we need to display those values.

N=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
for i in `seq 1 ${N}`
do
	eval "$(echo var${i})"=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
done

for i in `seq 1 ${N}`
do
	eval echo -n $(echo $`eval echo "var${i},"`)
done

> 6,56,31,11,89,49,26,9,14,77,8,90,55,87,39,63,99,28,12,1,43,80,44,87,27,

So we just created a random number of variables assigned random values within the established constraints. If you don’t want to deal with the hard-to-predict “eval”, a far more elegant solution is to use a shell array. Here’s an example that produces a similar result:
N=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
typeset -A array
for i in `seq 1 ${N}`
do
array[var${i}]=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
done
echo ${array[*]}

> 37 77 21 39 73 5 11 47 2 6 91 67 69 70 34 30 61 49 67 46 82 69 68 18

Thus, the unsightly construct
i=1 ; eval echo $(echo $`eval echo "var${i}"`)

can be replaced with a less cumbersome
i=1 ; echo ${array[var${i}]}

1
# In this case $i contains characters that cannot be used in a Bash variable name

$ i="12-23=32#"
$ echo var$i
var12-23=32#

# The "var12-23=32#" cannot be a variable name. When assigning variable value, we will need to replace all non-alphanumeric characters with underscores.

eval "$(echo var${i//[^[:alnum:]]/_})"=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
eval echo $(echo $`eval echo "var${i//[^[:alnum:]]/_}"`)

# The variable name will become "var12_23_32_", so the last line above should show the same value as:

echo $var12_23_32_

The inline replacement also works when using the array:
N=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
typeset -A array
for i in `seq 1 ${N}`
do
array[var${i//[^[:alnum:]]/_}]=$(echo "`expr ${RANDOM} % 100`+1"|bc -l)
done
echo ${array[*]}

> 90 24 43 64 52 50 82 75 69 84 91 38 61 28 41 84 56 5 26

 

Print Friendly, PDF & Email
  1. Note: Bash variable names may contain only alphanumeric characters and the underscore. To avoid naming problems when setting dynamic variable name, you can use inline substitution.

Leave a Reply