Linux小推车

Linux命令之eval - 动态执行命令

2019-03-20  本文已影响1人  白菜代码小推车

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会解开变量得到最后的字符串。

作用

  1. eval命令行
pipe="|"
cmd="ls "${pipe}" wc -l"
eval $cmd
  1. 得到最后一个变量
eval echo \$$#

第一遍扫描后,shell把反斜杠去掉了。当shell再次扫描该行时,它替换了$4的值,并执行echo命令

  1. 何用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了。

注意

  1. eval 不能获得函数处理结果。

  2. eval 嵌套无意义,在其他语言中可以通过 eval(eval(“code”)) ,来执行(执行动态生成的 code 的返回),而由于shell 中 eval 将后面的 eval 命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。

  3. 如果变量中包含任何需要shell直接在命令行中看到的字符(不是替换的结果),就可以使用eval。命令行结束符(; | &),I/o重定向符(< >)和引号就属于对shell具有特殊意义的符号,必须直接出现在命令行中。

参考

上一篇下一篇

猜你喜欢

热点阅读