2010-05-24 123 views
10

是否有这样做懒的评价比下面的更优雅的方式:懒评价猛砸

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

结果:

 
1 and 2 

它的工作原理,但eval "echo ..."只是觉得草率,并可能以某种方式不安全。在Bash中有更好的方法吗?

+0

我很好奇,为什么你想干什么这或你实际上想要完成的是什么。有时''eval'是正确或唯一的出路,但'declare'和'printf'的特殊功能可能是有用的。而且可能还有其他方法可以完成你所追求的目标。 – 2010-05-24 23:28:19

+0

我有一个bash脚本,我想要可配置。我希望用户能够指定一个“模式”。之后,模式中的一些变量将被脚本运行的活动(SQL查询,SOAP调用和其他内部实用程序)替换并传递给另一个命令行程序。对于Bash,我有点新鲜感,并且对这种方法感觉不对。感谢您询问更多细节。 – User1 2010-05-25 03:07:18

回答

4

只要价值不来自不可靠的来源,就没有安全风险。有一些替代方案,不过,你可以从的gettext使用命令envsubst,例如:

$ pattern='$x and $y' 
$ x=1 y=2 envsubst <<< $pattern 
1 and 2 
+0

我认为这种情况下的安全问题有点偏执。我喜欢多余的引号。 – User1 2010-06-03 15:18:09

0

你说得对,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'。那么输出将是“满月熄灭,天空清晰,所以狼人必须活跃。”

+1

答案与问题的例子相符。但对于基本字符串替换更复杂的任何东西来说,它似乎都不是很有用。如果我试图遵循这种方法,我必须在Bash中编写一个Bash解释器。 – ceving 2014-10-21 08:49:09

+0

我的答案是将脚本与用户的不可信输入隔离的一种方法。它基于OP针对我的查询附带的问题的评论。 – 2018-02-22 23:38:48

2

一个安全的可能性是使用的函数:

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

这就是全部。然后使用方法如下:

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

你甚至可以使用xy作为环境变量(以使它们不在主范围设置):

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

这是我要写的,如果它还没有在这里的答案。 (再次,我根据已经添加的答案,将它弹回到首页,我完全发现了这个问题)。 :) – 2018-02-23 22:47:07