Tell me more ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I was wanting to initialize some strings at the top of my script with variables that have no yet been set, such as:

str1='I went to ${PLACE} and saw ${EVENT}'
str2='If you do ${ACTION} you will ${RESULT}'

and then later on PLACE, EVENT, ACTION, and RESULT will be set. I want to then be able to print my strings out with the variables expanded. Is my only option eval? This seems to work:

eval "echo ${str1}"

is this standard? is there a better way to do this? It would be nice to not run eval considering the variables could be anything.

share|improve this question

2 Answers

up vote 4 down vote accepted

With the kind of input you show, the only way to leverage shell expansion to substitute values into a string is to use eval in some form. This is safe as long as you control the value of str1 and can ensure that it only references variables that are known as safe (not containing confidential data) and doesn't contain any other unquoted shell special character. You should expand the string inside double quotes or in a here document, that way only "$\` are special (they need to be preceded by a \ in str1).

eval "substituted=\"$str1\""

It would be a lot more robust to define a function instead of a string.

fill_template () {
  sentence1="I went to ${PLACE} and saw ${EVENT}"
  sentence2="If you do ${ACTION} you will ${RESULT}"
}

Set the variables then call the function fill_template to set the output variables.

PLACE=Sydney; EVENT=fireworks
ACTION='not learn from history'; RESULT='have to relive history'
fill_template
echo "During my holidays, $sentence1."
echo "Cicero said: \"$sentence2\"."
share|improve this answer
1  
Nice work using a function to delay evaluation, and to avoid the explicit eval call. – Clayton Stanley Jan 10 at 5:08

You can use placeholders for string templates instead of unexpanded variables. This will get messy pretty quickly. If what you are doing is very template heavy, you may want to consider a language with a real template library.

format_template() {
    changed_str=$1

    for word in $changed_str; do
        if [[ $word == %*% ]]; then
            var="${word//\%/}"
            changed_str="${changed_str//$word/${!var}}"
        fi
    done
}

str1='I went to %PLACE% and saw %EVENT%'
PLACE="foo"
EVENT="bar"
format_template "$str1"
echo "$changed_str"

The downside to the above is that the template variable must be it's own word (eg you can't do "%prefix%foo"). This could be fixed with some modifications, or simply by hard-coding the template variable instead of it being dynamic.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.