Updating a variable within a variable

I am trying to increment a counter variable that sits within a seperate text variable. I am initializing the counter variable once only at the start of my code. I expected to be able to increment the counter and have the text variable (that countains the counter) display as incremented throughout my code, only this isn't the case.

For example, using a text file containing the word "hello" as it
s contents. I expected the code below to give me 2 seperate text files like so:

run1.txt "testing1"
run2.txt "testing2"

The issue is, I'm receiving:

run1.txt "testing1"
run2.txt "testing1"
!/bin/bash

run_number=0

((run_number++)) #run_number is now 1

run="testing$run_number" #run is now 'testing1'

echo $run_number #displays 1

cp template.txt run1.txt #make a copy of a file that contains "hello"

sed -i 's#hello#'$run'#g' run1.txt #replace "hello" with var run ("testing1")

cat run1.txt #display new contents of file, "testing1"

echo "--------------------------------------------"

((run_number++)) #increment variable so that now, run_number=2

echo $run_number #displays 2

cp template.txt run2.txt #make copy of file that contains "hello"

sed -i 's#hello#'$run'#g' run2.txt #replace "hello" with "testing2"

cat run2.txt #display "testing2"?? this returns testing1

I am aware that I can simply initialize the variable..

run="testing$run_number" #run is now 'testing1

later on, after incrementing "run_number" but this seems redundant.

Any help is appreciated.

F

What you call "sitting within" is never the case.
After the assignment:

run="testing$run_number"

The variable run simply contains the string testing1
There is no variable contained in another variable..

1 Like

I see. Do you know if there is a way to increment a variable within a variable and have it remain throughout? I don't want it to be a one time thing because I plan on incrementing it in a for loop over several iterations.

Hi,

Not really, no. In Bash, variables are only ever updated at the time something is assigned to them. If other variables that were used to determine their value are themselves updated, this will not change the values of other variables dynamically.

A quick example is probably the easiest way to demonstrate this.

#!/bin/bash

number=1
string="Testing"

var=$string$number
echo "number: $number"
echo "string: $string"
echo "var: $var"
echo "---"

number=2
echo "number: $number"
echo "string: $string"
echo "var: $var"
echo "---"

var=$string$number
echo "number: $number"
echo "string: $string"
echo "var: $var"
echo "---"

Here's what you'll see when you run this.

$ ./script.sh 
number: 1
string: Testing
var: Testing1
---
number: 2
string: Testing
var: Testing1
---
number: 2
string: Testing
var: Testing2
---
$ 

So basically, the contents of a variable will only ever be updated when something is assigned to that variable, regardless of what happens to any other variables that were originally used to determine the contents of the variable in question.

Hope this helps clear things up.

I think you really have to rebuild the run variable every time you increment the integer variable.
Examples:

((run_number++))
run=running$run_number
# or
run=running$((++run_number))

Andrew

Or try a loop

#!/bin/bash
for ((run_number=1; run_number<=2; run_number++))
do
  run=testing$run_number
  runfile=run${run_number}.txt
  cp "template.txt" "$runfile"
  echo "$run_number"
  sed -i "s#hello#${run}#g" "$runfile" #replace "hello" with var run
  cat "$runfile" #display new contents of file 
  echo "--------------------------------------------"
done

Technically no. You can, of course, play dirty tricks:

 
container='abc${myvar}xyz'
myvar=4711
actual_value=$(eval "echo $container")

But it might be the case that your colleagues start saying nasty things to you if you are actually doing it in productive code :wink:

Another possibility is to use a function, which bypasses the eval:

container()
{
   echo "abc${myvar}xyz"
}
myvar=4711
actual_value=$(container)

Very true! ;-)) eval is the command which sole purpose is to be avoided, so to say.

In a stricter sense this is also problematic. You need to know in the main program, that the variable in container() is named in a certain way (here "myvar"). You could alleviate this dependency by doing:

container()
{
   echo "abc${1}xyz"
}
myvar=4711
actual_value=$(container $myvar)

This could indeed be an improvement, or not, depending on the context.

If application logic tells us that this variable always MUST be the same (for example, if it is an environment variable with an application-wide well-defined meaning, such as USER or CLASSPATH or OUR_GIT_REPO, I think it is better not to pass it as parameter. Having always the same parameter is annoying to type and invites typing mistakes. If this context is used with different variables often (i.e. our function container works a bit like a "formatter" for values), your approach is better.