24

此脚本中的最后一行不会像我预期的那样工作:

myfile="afile.txt"
mycmd='cat $myfile'
eval $mycmd
echo eval $mycmd

这里 echo 打印 'eval cat $myfile'。如何打印“eval cat afile.txt”?

4

4 回答 4

50

让我们一步一步来:

当你这样做时:

mycmd='cat $myfile'

您可以防止外壳插值$myfile。因此:

$ echo $mycmd
cat $myfile

如果要允许插值,可以使用双引号:

$ mycmd="echo $myfile"  #Double quotes!
$ echo "$mycmd"
cat afile.txt

当然,这会冻结$mycmd何时执行eval.

$ myfile="afile.txt"
$ mycmd="echo $myfile"
$ echo $mycmd
cat afile.txt
$ eval $mycmd   #Prints out afile.txt
$ myfile=bfile.txt
$ eval $mycmd   #Still prints out afile.txt and not bfile.txt

将此与以下内容进行比较:

$ myfile="afile.txt"
$ mycmd='cat $myfile'   #Single quotes hide $myfile from the shell
echo $mycmd
cat $myfile             #Shell didn't change "$myfile", so it prints as a literal
$ eval $mycmd           #Prints out afile.txt
$ myfile=bfile.txt
$ eval $mycmd           #Now prints out bfile.txt

您可能想要做的是$mycmd在回显时评估回显语句中的 :

$ echo $(eval "echo $mycmd")
$ cat afile.txt
$ myfile=bfile.txt
$ echo $(eval "echo $mycmd")
cat bfile.txt
于 2013-08-13T21:57:46.073 回答
13

你可以写:

eval echo eval $mycmd

或者更健壮一点:

eval echo eval "$mycmd"

也就是说,我建议eval尽可能避免;它往往非常脆弱,因为在 Bash 命令行处理中有许多复杂的步骤,而使用eval通常意味着您将多次执行这些步骤。很难跟踪真正发生的事情。

于 2013-08-13T21:12:30.340 回答
3

您需要评估回声,而不是相反:

eval echo "eval $mycmd"

或者

eval echo eval "$mycmd"

我认为前者更可取,但至少引用变量扩展。

于 2013-08-13T21:11:22.880 回答
1

如果您使用的是 bash,则更好的方法是使用数组:

myfile="afile.txt"
mycmd=(cat "$myfile")
echo "${mycmd[@]}"
"${mycmd[@]}"
于 2013-08-13T21:18:43.880 回答