eval - 动态执行命令
简述:eval会将后接的字符串当作shell命令执行。为什么说是“动态”的呢?这个命令可以把字符串里面的变量替换,这样如果写循环或者之类的,eval后接的字符串一样但是可能命令就不一样了,这样就发生变化,就是动态的执行命令。
最近看到别人代码中用到了eval
,感觉就像是发现了宝藏一样,之前不知道这个命令,就是想以后能不能用它来一点骚(tou)操(dian)作(lan)呢?在网上查了一些文章,很多都写得很好,但是对于一些示例代码没有给出详细的解释,这里我尝试用自己的想法来解释一波。这篇介绍中的部分示例代码来自于这些文章,文章的链接在文末。
用法
eval string
例子
- 执行用管道连接的命令
eval "ls | grep XXX | wc -l"
- 变量替换之后再执行命令
task="cat 123.txt | awk {NR%4==1{print}}"
eval $task
- 执行多个命令(如果命令先后顺序执行,它们之间用
;
隔开)
eval "data;bash 123.sh"
执行过程
eval会对后面的命令进行两遍扫描
比如下面有一个字符串,使用eval执行它。在eval后面接的是一个变量,在使用eval执行的时候的步骤是怎样的呢?
cmd="ps | grep 'bash'"
eval ${cmd}
- 原始字符串
eval ${cmd}
- 第一步:变量替换
eval "ps | grep 'bash'"
- 第二步:执行命令
ps | grep 'bash'
那问题来了,如果能变量替换的话,那如果变量还是指向变量eval会解开它得到最终的对应的那个字符串呢?
下面这个例子有点粗暴了,但是拿来演练还是可以滴。
t1="ls"
t2="${t1} -l"
str="${t2} | wc -l"
eval ${str}
最后的结果是对的。
我们可以来尝试想一下eval的对于变量的变化的过程
原始 | 第一步 | 第二步 | 第三步 |
---|---|---|---|
${str} |
${t2} | wc -l |
${t1} -l | wc -l |
ls -l | wc -l |
也就是按照上面的情况,解开的顺序${str}
-> ${t2}
-> ${t1} -l
-> ls -l
之后执行ls -l | wc -l
命令。也就是说eval会解开变量得到最后的字符串。
作用
- eval命令行
pipe="|"
cmd="ls "${pipe}" wc -l"
eval $cmd
- 得到最后一个变量
eval echo \$$#
第一遍扫描后,shell把反斜杠去掉了。当shell再次扫描该行时,它替换了$4的值,并执行echo命令
- 何用eval命令创建指向变量的“指针”
x=100
ptrx=x
eval echo \$$ptrx # 指向ptrx,用这里的方法可以理解b中的例子
# 100 打印100
eval $ptrx=50 # 将50存到ptrx指向的变量中。
echo $x
# 50 打印50
首先将变量x
赋值,之后将x
这个字符串复制给ptrx
,在这里ptrx
对应的值就是x
这个简单的字符。但是当这个x
前面加上$之后,x
的身份不同了,它指向的就是那个赋予x
的值。在\$$ptrx
中,首先eval将$ptrx
转为它对应的值x
,然后执行echo $x
这个命令,对应的值就是100
啦。之所以第一个$符号前面加反斜线就是不想让这个$有特殊含义。
之后eval $ptrx=50
,这个同样的,先变量替换,然后执行x=50
这样一句话。这样x
就又被赋值为50了。
注意
-
eval 不能获得函数处理结果。
-
eval 嵌套无意义,在其他语言中可以通过 eval(eval(“code”)) ,来执行(执行动态生成的 code 的返回),而由于shell 中 eval 将后面的 eval 命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。
-
如果变量中包含任何需要shell直接在命令行中看到的字符(不是替换的结果),就可以使用eval。命令行结束符(; | &),I/o重定向符(< >)和引号就属于对shell具有特殊意义的符号,必须直接出现在命令行中。
网友评论