0

I have a variable, $var_c which contains a lot of complex syntax. I'd rather not need to rewrite this many times, as it is easy to make a mistake. But sometimes the data changes.

#!/bin/bash

var_a="cat"
var_b="dog"

var_c="<div class=\"pet_a\">$var_a</div><div class=\"pet_b\">$var_b</div>"

echo $var_c

var_a="fish"
var_b="whale"

echo $var_c

This should first <div class="pet_a">cat</div><div class="peg_b">dog</div> then <div class="pet_a">fish</div><div class="peg_b">whale</div>, however, after changing the variables $var_a and $var_b, $var_c is not updated.

How can I tell BASH to update this variable, without having to completely provide all of the syntax again?

3 Answers 3

5

Use a Shell Function Instead

In Bash, interpolation in an assignment happens at the time of assignment. So, you can't really do what you're trying to do with a variable. Instead, you should use a shell function. For example:

var_a="cat"
var_b="dog"
var_c () {
    echo "<div class=\"pet_a\">$var_a</div><div class=\"pet_b\">$var_b</div>"
}
echo $(var_c)
# <div class="pet_a">cat</div><div class="pet_b">dog</div>

var_a="fish"
var_b="whale"
echo $(var_c)
# <div class="pet_a">fish</div><div class="pet_b">whale</div>

Note that in this case you could call var_c directly, rather than echo $(var_c), since the function already includes an echo statement. I deliberately used that in the example to maintain your current semantics, and to show how you can use a shell function like a variable.

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

Comments

3

Use a Printf Format String

In Bash, interpolation in an assignment happens at the time of assignment. So, you can't really do what you're trying to do with a variable. One way to address this is with a format string and the printf builtin. The builtin supports a -v flag, which says:

  -v var    assign the output to shell variable VAR rather than
            display it on the standard output

For example:

fmt="<div class=\"pet_a\">%s</div><div class=\"pet_b\">%s</div>"
var_a="cat"
var_b="dog"
printf -v var_c "$fmt" "$var_a" "$var_b"
echo "$var_c"
# <div class="pet_a">cat</div><div class="pet_b">dog</div>

var_a="fish"
var_b="whale"
printf -v var_c "$fmt" "$var_a" "$var_b"
echo "$var_c"
# <div class="pet_a">fish</div><div class="pet_b">whale</div>

Comments

1

Variables contain data, not logic. When you set a variable, you're setting it to a particular value, not the rules for computing that value. If you want something that returns different results at different times, you need something more like a function:

func_c() {
    echo "<div class=\"pet_a\">$var_a</div><div class=\"pet_b\">$var_b</div>"
}

var_a="cat"
var_b="dog"
echo "$(func_c)"  # echoes '<div class="pet_a">cat</div><div class="pet_b">dog</div>'

var_a="fish"
var_b="whale"
echo "$(func_c)"  # echoes '<div class="pet_a">fish</div><div class="pet_b">whale</div>'

Note that executing a function uses the syntax $(functionname) (this can actually be used with any command), instead of just $variablename for variables. Also, you should almost always put both function and variable references in double-quotes (as I did above). Also also, if you're really just printing the result, don't use echo "$(functionname)" as I did above, just use functionname directly. Finally, it's generally bad practice to make functions depend on global variables (var_a and var_b) -- they should receive the data they're going to operate on as arguments:

func_c() {
    # Usage: func_c var_a var_b
    echo "<div class=\"pet_a\">$1</div><div class=\"pet_b\">$2</div>"
}

func_c "cat" "dog"  # echoes '<div class="pet_a">cat</div><div class="pet_b">dog</div>'
func_c "fish" "whale"  # echoes '<div class="pet_a">fish</div><div class="pet_b">whale</div>'
var_d="$(func_c "ferret" "weasel")"  # sets var_d to '<div class="pet_a">ferret</div><div class="pet_b">weasel</div>'

(I used more double-quotes than are strictly necessary in the above example -- but it's better to use them when not needed than to leave them off when they are needed.)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.