“有时候你以为是春天来了,却往往被冻死在这个曾经欣羡的季节”
eval - construct command by concatenating arguments
通俗而不专业的来讲,就是将传递给eval的所有args连接起来,作为一条shell命令来执行,并且在连接的同时,会将第一层变量所指向的值,作为实际连接的内容。
用官方的例子来解释:
#定义变量foo,内容为hello
foo=hello
#定义变量x,内容为foo
x=foo
#这个时候,x和foo都是独立的变量,两者没有任何关系。接着重新定义一个新变量y
y='$'$x
#这是什么意思呢,就是将就是将x变量的值传递给y,并在值的前面加一个$符号,此时y的值就是$foo,这是shell默认解析的结果,如果再深入将这种类似变量引用方式表示的字符解析为其代表的值呢,常规是没有办法的,这时候用eval就可以实现
eval y='$'$x
#加上eval的实际效果是什么呢,其实就是将$foo再取一次值,因为$foo是标准的shell变量模式,所以最终y得到的结果就是$foo变量所指的内容,也就是hello。
这能解决什么问题呢,类似下面这样的一个问题:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#!/bin/sh labels="test1 test2 test3" for item in $labels do if [ -s "${test}.log" ];then ${item}_color="red" else ${item}_color="green" fi echo ${item}_color done |
我们希望将一个变量中的内容,作为新变量名称的一部分来定义一个新的变量,上面的脚本在执行的时候会提示错误:
1 2 3 4 5 6 7 8 |
evalTry.sh: 9: evalTry.sh: test1_color=green: not found test1_color evalTry.sh: 9: evalTry.sh: test2_color=green: not found test2_color evalTry.sh: 9: evalTry.sh: test3_color=green: not found test3_color |
从错误中能看到什么呢,有两点:
1.shell将${item}_color="green"最终解析为test1_color=green,并将其作为一条命令来执行了,当然这个命令是不存在的,所以提示not found
2.echo ${item}_color打印了变量替换之后内,而不是我们理想中新增变量所指向的值,也就是red或者green
这个时候,我们换一种写法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
bin/sh labels="test1 test2 test3" for item in $labels do if [ -s "${test}.log" ];then eval ${item}_color="red" else eval ${item}_color="green" fi eval echo '$'${item}_color done |
执行结果就变为下面这样的:
1 2 3 4 5 6 |
jma:/work/study/shell$ sh evalTry.sh green green green |
最后的eval echo只是为了演示,实际上可以直接通过echo $test1_color的方式来验证,我们希望的变量确实已经创建好了。这就是eval的功能。