Is there more elegant way of doing lazy evaluation than the following:
pattern=\'$x and $y\' x=1 y=2 eval \"echo $pattern\"
results:
1 and 2
You can use the command envsubst from gettext, for example:
$ pattern='x=$x and y=$y'
$ x=1 y=2 envsubst <<< $pattern
x=1 and y=2
You're right, eval
is a security risk in this case. Here is one possible approach:
pattern='The $a is $b when the $z is $x $c $g.' # simulated input from user (use "read")
unset results
for word in $pattern
do
case $word in
\$a)
results+=($(some_command)) # add output of some_command to array (output is "werewolf"
;;
\$b)
results+=($(echo "active"))
;;
\$c)
results+=($(echo "and"))
;;
\$g)
results+=($(echo "the sky is clear"))
;;
\$x)
results+=($(echo "full"))
;;
\$z)
results+=($(echo "moon"))
;;
*)
do_something # count the non-vars, do a no-op, twiddle thumbs
# perhaps even sanitize %placeholders, terminal control characters, other unwanted stuff that the user might try to slip in
;;
esac
done
pattern=${pattern//\$[abcgxz]/%s} # replace the vars with printf string placeholders
printf "$pattern\n" "${results[@]}" # output the values of the vars using the pattern
printf -v sentence "$pattern\n" "${results[@]}" # put it into a variable called "sentence" instead of actually printing it
The output would be "The werewolf is active when the moon is full and the sky is clear." The very same program, if the pattern is 'The $x $z is out $c $g, so the $a must be $b.' then the output would be "The full moon is out and the sky is clear, so the werewolf must be active."
One safe possibility is to use a function:
expand_pattern() {
pattern="$x and $y"
}
That's all. Then use as follows:
x=1 y=1
expand_pattern
echo "$pattern"
You can even use x
and y
as environment variables (so that they are not set in the main scope):
x=1 y=1 expand_pattern
echo "$pattern"