2010-05-24 151 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