6

In Bash, I'm trying to increment a counter variable (number) from within a text string. If I call the counter var alone it increments successfully, but If I echo the string variable on each iteration of my loop, the counter variable does not increment.

#!/bin/bash

number=1

yes="number$number/"

for i in 1 2 3
do
    echo $number

    echo $yes

    ((number++))

done

I get this output:

1
number1/
2
number1/
3
number1/

Whereas I expect this:

1
number1/
2
number2/
3
number3/

I have also tried this:

yes="number${number}/"

..which gave the same incorrect result.

Thanks

3
  • 2
    yes="number$number/" is assigned once. It does not update when the value of $number changes. Commented May 1, 2017 at 2:08
  • Do you know how I would get the $number variable in the string to update when $number changes? Commented May 1, 2017 at 2:11
  • 1
    @Jon: You cannot. Expansion happens only at the time of assignment. You'll have to move the assignment to the place where you have the right value in $number instead. Commented May 1, 2017 at 2:14

3 Answers 3

9
for i in 1 2 3
do
    echo $number
    yes="number$number/"
    echo $yes

    ((number++))

done
Sign up to request clarification or add additional context in comments.

Comments

3

As you've been told in comments, expansion happens at the time of assignment. The variable $yes contains a string which includes the value of $number at the time of assignment. After assignment, there is nothing in the content of $yes which would indicate any connection to the variable $number.

There are two common ways to get this kind of functionality.

First, you can use eval.

#!/usr/bin/env bash

number=1

yes='number$number/'    # note the single quotes

for i in 1 2 3; do

    echo "$number"
    eval "echo \"$yes\""
    ((number++))

done

Note that the value of $yes is NOT being updated here -- it's simply being used to expand what is printed by echo.

You will find that many people discourage the use of eval, as it can have unintended security related consequences.

Second, you could just update yes each time you run through the loop.

#!/usr/bin/env bash

number=1

for i in 1 2 3; do

    echo "$number"

    yes="number$number/"
    echo "$yes"

    ((number++))

done

If you're looking to use this for formatting, then printf is your friend:

#!/usr/bin/env bash

number=1

yesfmt='number%d\n'

for i in 1 2 3; do

    echo "$number"
    printf "$yesfmt" "$number"
    ((number++))

done

Without knowing the bigger picture or what you're trying to achieve, it's difficult to recommend a strategy.

Comments

2

Use a function (I changed the name from yes to report because yes is a standard posix utility, and anyway it wasn't at all descriptive.)

#!/bin/bash
number=1
report() { echo "number$number/"; }
for i in 1 2 3; do
  echo $number
  report
  ((number++))
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.