Есть ли более элегантный способ ленивой оценки, чем следующее:
pattern='$x and $y'
x=1
y=2
eval "echo $pattern"
результаты:
1 and 2
Это работает, но eval "echo ..."
просто чувствует себя неряшливым и может быть каким-то образом небезопасным. Есть ли лучший способ сделать это в Bash?
Ответ 1
Вы можете использовать команду envsubst из gettext, например:
$ pattern='$x and $y'
$ x=1 y=2 envsubst <<< $pattern
1 and 2
Ответ 2
Одна безопасная возможность - использовать функцию:
expand_pattern() {
pattern="$x and $y"
}
Это все. Затем используйте следующее:
x=1 y=1
expand_pattern
echo "$pattern"
Вы даже можете использовать x
и y
в качестве переменных среды (чтобы они не были установлены в основной области):
x=1 y=1 expand_pattern
echo "$pattern"
Ответ 3
Вы правы, eval
- это риск безопасности в этом случае. Вот один из возможных способов:
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
Результат будет "Оборотень активен, когда луна заполнена, а небо прозрачно". Сама же программа, если шаблон равен '$ x $z вне $c $g, поэтому $a должен быть $b.' то выход будет "Полная луна исчезнет, и небо станет ясным, поэтому оборотень должен быть активным".