Ленивая оценка в Bash - PullRequest
       13

Ленивая оценка в Bash

11 голосов
/ 25 мая 2010

Есть ли более элегантный способ выполнения ленивых вычислений, чем следующий:

pattern='$x and $y'
x=1
y=2
eval "echo $pattern"

Результаты:

1 and 2

Это работает, но eval "echo ..." просто кажется неаккуратным и может быть небезопасным в некотором смысле Есть ли лучший способ сделать это в Bash?

Ответы [ 3 ]

5 голосов
/ 02 июня 2010

Вы можете использовать команду envsubst из gettext , например:

$ pattern='$x and $y'
$ x=1 y=2 envsubst <<< $pattern
1 and 2
4 голосов
/ 24 февраля 2018

Одна безопасная возможность - использовать функцию:

expand_pattern() {
    pattern="$x and $y"
}

Вот и все. Затем используйте следующее:

x=1 y=1
expand_pattern
echo "$pattern"

Вы даже можете использовать x и y в качестве переменных среды (чтобы они не задавались в основной области):

x=1 y=1 expand_pattern
echo "$pattern"
0 голосов
/ 25 мая 2010

Вы правы, 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». тогда вывод будет "Полная луна и небо чистое, поэтому оборотень должен быть активен".

...