eval可以读取一连串的参数,然后按照参数特性来执行。
eval会对后面的命令进行两遍扫描,如果第一遍扫描后,命令是个普通命令,则执行此命令;如果命令中含有变量的间接引用,则保证间接引用的语义。也就是说,eval命令将会首先扫描命令行进行所有的置换,然后再执行该命令。因此,eval命令适用于那些一次扫描无法实现其功能的变量。
eval 执行以下两个步骤:
第一步,执行变量替换,类似与C语言的宏替代;
第二步,执行替换后的命令串。
这里只简单介绍两种基本用法:
1、执行含有带字符串的命令
我们可以新建一个文件leo将字符串“I am leo”!“写入文件中,把cat leo赋值给变量content,如果我们echo content并不能的到leo中的内容;然而eval content则能显示文件中的内容,因为eval命令对后面的命令进行了两次扫描,第一次将content替换为 cat leo,第二次执行cat leo。
[xxx@xxx xxx]$ vi leo //新建leo文件并写入字符串
[xxx@xxx xxx]$ vi eval_test.sh //新建脚本文件并编辑
#!/bin/bash
content="cat leo"
echo $content
eval $content
[xxx@xxx xxx]$ ./eval_test.sh
cat leo
I am leo
[xxx@xxx xxx]$
这些需要进行两次扫描的变量有时被称为复杂变量。不过这些变量本身并不复杂。eval命令不仅可以回显复杂变量,也可以用于回显简单变量。
2、回显简单变量
#!/bin/bash
content=leoisthebest #content存储的是普通变量,不是命令
echo $content
eval echo $content #注意这里的echo不可以丢,否则eval执行会出错
[xxx@xxx xxx]$ ./eval_test.sh
leoisthebest
leoisthebest
[xxx@xxx xxx]$
接下来是我在实际shell编程过程中遇到的一个情况,做个记录,有兴趣的可以看一看
#!/bin/bash
Get_value()
{
eval "echo \${$1}" #引号内进行初次变量替换后为"echo \${val}",去掉引号等价于 echo $val
}
main()
{
val="success"
get=val #此处并非像C中一样将val的值赋值给get,而是将“val”这个字符串赋值给get
ret=`Get_value $get`
}
main $* #调用main
[xxx@xxx xxx]$ ./eval_test.sh
success
[xxx@xxx xxx]$
调用‘Get_value’函数的时候,参数是get的值即字符串‘val’,在函数体内部,代码
eval "echo \${$1}" #$1为函数的第一个参数,此处即val
转换为
eval "echo \${val}"
由于引号包含所以加了转义符'\',去掉引号变为
eval echo $val
接下来就不难理解了,最后ret接收到的值就相当于执行“echo $val”的结果,此处结果为success。
如果get变量存储的是一个普通字符串,当eval执行到 “echo $val”时,由于val没有意义,则会打印出空值,当val本身也有值时,才能成功替换并打印。