使用eval'$ cmd'执行变量将生成错误

时间:2013-08-23 13:06:50

标签: linux bash shell eval cat

如果我将cat命令保存到字符串然后执行它,那么我将收到错误

linux# cmd="cat /data/test/test.tx* | grep toto"
linux# eval '$cmd'
cat: |: No such file or directory
cat: grep: No such file or directory
cat: toto: No such file or directory

即使

linux# $cmd
cat: |: No such file or directory
cat: grep: No such file or directory
cat: toto: No such file or directory

我知道

linux# eval "$cmd"

有效,但在我的脚本中我想使用eval '$cmd'

如何将cat命令保存到变量中时执行它?

现在,如果cmd="echo anymessage"那么

linux# eval '$cmd'
linux# $cmd
linux# eval "$cmd"

所有这些都可以使用

3 个答案:

答案 0 :(得分:5)

让我们从一个简单的命令开始,它可以以任何方式工作,但出于不同的原因。

$ cmd="echo anymessage"
$ eval '$cmd'

eval '$cmd' eval处理字符串$cmd。它将它分成单词,这又是单个单词$cmd。它将参数扩展为echo anymessage并执行一轮分词以获得echoanymessage。现在,echo是命令,anymessage是参数,执行echo命令。

$ eval "$cmd"

此处,eval正在处理字符串echo anymessage,因为bash在执行$cmd之前已在eval 上执行了参数展开。该字符串再次拆分为单词,echo被识别为命令。

现在,让我们为cmd使用更复杂的值。

$ cmd="cat /data/test/test.tx* | grep toto"
$ eval '$cmd'

同样,eval收到文字字符串$cmd。这是整个命令行,在分词后,所以这是一个简单的命令:没有管道,没有重定向等。参数扩展为字符串cat /data/test/test.tx* | grep toto。接下来,单词拆分会生成单词cat/data/test/test.tx*|greptoto。发生路径名扩展 关于模式;我们只是说它扩展为单个文件名/data/test/test.txt。您现在有5个单词,不再执行扩展,因此shell在命令位置标识单词cat,并以剩余的4个单词作为参数运行。 cat无法找到名为|greptoto的文件时发生错误。

最后,让我们使用双引号

$ eval "$cmd"

这次,eval接收扩展字符串cat /data/test/test.tx* | grep toto作为命令行。分词后,会看到cat/data/test/test.tx*|greptoto。这个多字命令行包含一个管道字符,因此eval将其作为管道处理。与前面的示例相比,eval的单个参数只包含一个单词$cmd。从这里开始,您应该能够看到管道是如何按预期执行的。


总之,如果它是包含您要解析和执行的复杂命令行的单个参数,则需要对eval的参数使用双引号。

答案 1 :(得分:1)

您需要告诉shell正常处理管道,而不是cat命令的一部分。一种方法是将它传递给shell的新实例。

sh -c "$cmd"

请注意,这会引入各种引用问题,最好不要尝试将shell元命令存储在变量中。

答案 2 :(得分:0)

另请注意,如果文件夹中没有文件,此代码将失败。这是将要抛出的错误:

  

cat:*:没有这样的文件或目录

要解决此问题,您可以启用nullglob

shopt -s nullglob