一、场景
eval会对后面的cmdLine进行两遍扫描,如果第一遍扫描后,cmdLine是个普通命令,则执行此命令;如果cmdLine中含有变量的间接引用,则保证间接引用的语义。
我不止一次遇到过这种问题。在shell给mysql传参,在shell给python传参,shell给数组传参。
区别就是在一些场景无伤大雅,一些场景就读不出这个值就无法执行下去。mysql -e传参就是这个情况。eval可以解决这个群情况,间接传参。
1.shell给数组传参
命令行执行
[root@jumpserver ~]# I=1;IP_LIST1[$I]=ip_list$I;echo ${IP_LIST1[@]}
ip_list1
shell脚本
[root@jumpserver ~]# echo 'I=1;IP_LIST1[$I]=ip_list$I;echo ${IP_LIST1[@]}' > 1.sh && sh -x 1.sh
+ I=1
+ IP_LIST1[$I]=ip_list1 #可以看到索引变量未解析出来(但其实这句话生效了),因为数组命令也是执行linux语句
+ echo ip_list1
ip_list1
使用eval
[root@jumpserver ~]# echo 'I=1;eval IP_LIST1[$I]=ip_list$I;echo ${IP_LIST1[@]}' > 1.sh && sh -x 1.sh
+ I=1
+ eval 'IP_LIST1[1]=ip_list1' #可以看到变量被具象成了一个值,同样生效了。
++ IP_LIST1[1]=ip_list1
+ echo ip_list1
ip_list1
2.shell给mysql
shell给mysql传参也会出现这个情况,这时候如果出现$I,mysql可没法向上面一样去解析。
这里就无法解读变量了。具体例子不分析了。
3.数组名引用变量得用法
例1:
eval echo '${'$ip_list'[@]}' #这里是数组名引用变量得用法
例2:
#!/bin/bash
aa="lsa"
ggg=0
ggg1=1
gggg="123"
gggg2="321"
eval $aa[$ggg]=$gggg
eval $aa[$ggg1]=$gggg2
eval item='${'$aa'[@]}'
eval echo $item
eval "for num in $item
do
echo \${num}
done"
二、eval详解(转)
举例如下:(其实我觉得我上面的例子更生动)
set 11 22 33 44
如果要输出最近一个参数,即44,可以使用如下命令,
echo $4
但是如果我们不知道有几个参数的时候,要输出最后一个参数,大家可能会想到使用$#来输出最后一个参数,
如果使用命令:
echo "\$$#"
则得到的结果是
4,而不是我们想要的44。这里涉及到一个变量间接引用的问题,我们的本意是输出
4
,
而
不
是
我
们
想
要
的
44
。
这
里
涉
及
到
一
个
变
量
间
接
引
用
的
问
题
,
我
们
的
本
意
是
输
出
4,默认情况下,命令后忽略变量间接引用的情况。
这时候,就可以使用eval命令。
eval echo "\$$#"
得到的结果为44
1.eval命令将会首先扫描命令行进行所有的替换,憨厚再执行命令。该命令使用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时候被称为复杂变量。
2.eval也可以用于回显简单变量,不一定时复杂变量。
NAME=ZONE
eval echo NAME等价于echo N A M E 等 价 于 e c h o NAME
3.两次扫描
test.txt内容:hello shell world!
myfile=”cat test.txt”
(1)echo $myfile #result:cat test.txt
(2)eval echo $myfile #result:hello shell world!
从(2)可以知道第一次扫描进行了变量替换,第二次扫描执行了该字符串中所包含的命令
4.获得最后一个参数
echo “Last argument is (evalecho$ ( e v a l e c h o $ #)”
echo “Last argument is (evalecho ( e v a l e c h o #)”