功能说明:重新运算求出参数的内容。8 z0 a6 I: Y: N! Y" m9 B
9 t) v3 H0 K/ A* S5 ~
语 法:eval [参数]
! z; h" e2 P6 s/ ~. C. K0 ~ T, m1 t
6 S# K$ j* ?# L; C0 J' w* R* P补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行。& \" V6 N. `) N$ n1 u
5 Q7 e) O+ A. b0 J0 @参 数:参数不限数目,彼此之间用分号分开。
( \0 F6 A' ]% a7 g( C j5 c1.eval命令将会首先扫描命令行进行所有的替换,憨厚再执行命令。该命令使用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时候被称为复杂变量。 2.eval也可以用于回显简单变量,不一定时复杂变量。 NAME=ZONE eval echo $NAME等价于echo $NAME 3.两次扫描 test.txt内容:hello shell world! (1)echo $myfile #result:cat test.txt (2)eval echo $myfile #result:hello shell world! 从(2)可以知道第一次扫描进行了变量替换,第二次扫描执行了该字符串中所包含的命令 4.获得最后一个参数 echo "Last argument is $(eval echo \$$#)" echo "Last argument is $(eval echo $#)"
. a0 o7 ]5 @9 h2 d7 g q+ i) z: kshell 也提供了 eval 命令,如同熟悉的其他脚本语言,会将它的参数做为命令执行,初看会疑惑为什么shell要提供两种动态执行命令字串的机制,但是经过仔细分析,才发现shell的eval同其他语言有很大区别。
7 C r, O' A; H x" Z& X+ V3 @/ @! w' b/ i+ c# [- x/ b
1.shell 中的函数虽然可以通过return 返回,但是这里的return 相当于 exit,只能是个状态值用于测试,而不能像其它语言一样返回复杂的结果,其处理结果只能通过输出到标准输出经过 `` ,$()取得。
6 W. G8 b+ @; u6 V1 c
! l, ~% d# l4 P$ ^+ _; N L; [2.shell 中的 eval8 e% ]) e$ T' S, S2 R" |. S' n+ b O& C
G' T' L, o/ ]5 ^! h1 o+ ~ 2.1 不能获得函数处理结果 ,如1所说,所有命令,函数的处理结果只能通过 ``来获得,那么其它语言中利用eval来获得动态生成代码执行后的输出变得不可能。
/ Z. s) F8 g. G1 `$ N
* r, h1 o, H2 P; X2 L( l0 F9 G) g 2.2 eval 嵌套无意义 ,在其他语言中可以通过 eval(eval("code")),来执行(执行动态生成的code的返回),而由于shell 中 eval 将后面的eval命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。 扩展阅读:eval命令使用示例详解 资料整理www.linuxso.com eval的作用是再次执行命令行处理,也就是说,对一个命令行,执行两次命令行处理。这个命令要用好,就要费一定的功夫。我举两个例子,抛砖引玉。6 u5 y6 Y% a2 V/ {* R3 I8 ]8 _0 e
- o, V0 T" s; Y" {
1、例子1:用eval技巧实现shell的控制结构for' W% i* W( n& N* S1 |$ y0 m
4 [- c/ d# q: Y用eval技巧实现shell的控制结构for。8 d* L3 g& g& n4 j: u. z1 M
, W _* K* X8 L" h3 j
[root@home root]# cat myscript1& L6 y7 ~* x& u9 W( y( R: Q
! r3 ^: C, g* e; K9 y& E$ ^* @4 @
QUOTE:
: `5 i2 b* q) @8 a/ [#!/bin/sh' w: s5 Q/ ]2 y: j
evalit(){* \1 N4 C% c3 l6 p
if [ $cnt = 1 ];then
# p' `3 D$ W3 r4 a2 j eval $@7 W. }2 T1 E C$ M- [% p6 B
return
/ p/ B' ]$ N: K2 X7 ` else3 H2 C& d }, A# h+ v; |2 J
let cnt="cnt-1"
( `3 e6 x# F4 Y$ H2 a evalit $@# a5 q3 |# J: r- H' Q9 C
fi
& B% K( Y- m8 N4 C+ a2 r% a eval $@3 O" k- `) w/ K5 N
}
' P, u* i i1 L% V: P# i" I Icnt=$1
% u: A- i) M7 j% G7 F6 o4 vecho $cnt | egrep "^[1-9][0-9]*$" >/dev/null' V, R* F9 `6 B
if [ $? -eq 0 ]; then' F0 }8 Q* P* @, j: ?3 U- |8 O
shift
% T. G' u! E$ ^8 v- p$ S evalit $@: V8 S, `0 [% z" E7 Q! k
else
3 b; t1 c6 v) \- u8 c echo 'ERROR!!! Check your input!'
p# @% B4 s1 W) Yfi
5 G' A4 n C: `& R[root@home root]# ./myscript1 3 hostname
. w9 g# a a2 n6 w- c2 |home! h% q* e' k: u- e- m4 N/ P! j4 N
home) p; `# v/ `9 R/ ?- U) F
home* H |1 C: T6 H. f. h9 W
[root@home root]# ./myscript1 5 id |cut -f1 -d' '
- i* @" G }+ i* P/ ]uid=0(root)) O0 m( S$ C& O( Q( e/ D# l
uid=0(root)( Z) }8 K5 p1 E& j1 K8 j$ G
uid=0(root)+ @. @4 o2 H6 q" \* n
uid=0(root)
9 A- Q e# p: P9 j Q/ E- ]uid=0(root)0 Q; {5 z8 g, S& w) R2 s
注意:bash里有两个很特殊的变量,它们保存了参数列表。
( J- k6 n# {: J$ @* |9 I$ S1 c# \* k8 P+ ?6 T1 |) b
$*,保存了以$IFS指定的分割符所分割的字符串组。
[" f# f' ]0 E" b' S$@,原样保存了参数列表,也就是"$1""$2"...7 I7 m4 a( ]* F
2 {1 r* m; }; }& S! k这里我使用了函数递归以及eval实现了for结构。8 y& z7 X9 c* P" N: y; _+ c
当执行eval $@时,它经历了步骤如下:
8 l. P# u0 E$ [! U3 Y' }第1步,分割成eval $@
1 k- j( S2 r/ u' Z8 B3 F6 g第6步,扩展$@为hostname
+ Z& X7 U: n8 P& B d# [. P. {第11步,找到内置命令eval
5 J2 R% P, `2 X f7 Y8 ~重复一次命令行处理,第11步,找到hostname命令,执行。: \( _! h% ]" o: z- M5 a' M Q% j
, `* s/ V( V+ U7 ^! o+ E6 x9 l注意:也许有人想当然地认为,何必用eval呢?直接$@来执行命令就可以了嘛。
1 ]. U X" m! Y, P
# p; h) u# C* [+ A: @例子2:一个典型错误的例子* t9 `. J1 x1 v; B
3 O9 Q, o8 |; H1 d. H) l/ \
错误!这里给个典型的例子大家看看。
' w% }4 s; x* i4 S g O+ ]3 M: y$ u: Q1 e# p, Q
1 l- A* k, {3 G- C
[root@home root]# a="id | cut -f1 -d' '"
. {& t1 O9 {4 M% w[root@home root]# $a, t6 [6 J' m5 T$ t/ ~, ]/ u
id:无效选项 # f) T" @( N8 h: j
请尝试执行‘id # help’来获取更多信息。$ _/ |3 v; V" p8 @, E
[root@home root]# eval $a
: p! P2 R% |" `+ e% a, Zuid=0(root)
9 t/ N2 P# f- z# E* |0 j
3 u3 [9 E( C) P如果命令行复杂的话(包括管道或者其他字符),直接执行$a字符串的内容就会出错。分析如下。
4 |4 F8 p! l/ j2 Q* s `' i* H$a的处理位于第6步──参数扩展,也就是说,跳过了管道分析,于是"|", "cut", "-f1", "-d"都变成了id命令的参数,当然就出错啦。
& _& H- d* |2 X9 X& [: q% B( U但使用了eval,它把第一遍命令行处理所得的"id", "|", "cut", "-f1", "-d"这些字符串再次进行命令行处理,这次就能正确分析其中的管道了。! Q J- R R+ n3 U
: a8 o8 ]: O( G" r% _: ?
总而言之:要保证你的命令或脚本设计能正确通过命令行处理,跳过任意一步,都可能造成意料外的错误!) {7 A2 m# d3 p- h
4 S& H0 j7 D# k* [' u例子3:设置系统的ls色彩显示
S2 {9 h' v: w" r1 v
4 _2 }8 U+ G2 \3 a: {( [4 l1 `( a, i. N
eval $(dircolors -b /etc/dircolors)
7 N1 [0 L- [7 N" m
! F1 a6 ?7 n! k( ~eval语句通知shell接受eval参数,并再次通过命令行处理的所有步骤运行它们。
8 J9 r D* v# z1 d( ?4 n/ f它使你可以编写脚本随意创建命令字符串,然后把它们传递给shell执行;" p/ R; P. B$ I. e4 |( H
$()是命令替换,返回命令的输出字符串。" P. s6 k& A' x: d% q0 G
其中dircolors命令根据/etc/dircolors配置文件生成设置环境变量LS_COLORS的bash代码,内容如下
% p5 p1 @; R5 h9 P
6 w# k7 y. h+ p- r; I[root@localhost root]# dircolors -b > tmp
9 {* ^- C1 _* J. ^# Z[root@localhost root]# cat tmp$ f/ R& ^1 d3 e, p" f6 s1 l" t
LS_COLORS='no=00:fi=00:di=01;34:ln=01; ......
' G7 u1 U: b9 M8 T6 N) Jexport LS_COLORS
- T8 u5 k. H$ a3 {0 u#这里我没有指定配置文件,所以dircolors按预置数据库生成代码。0 L+ |" {% u1 T4 {- w0 c
其输出被eval命令传递给shell执行。: K2 Z" v& q# s5 z0 T, y
- Z" ?$ Z! z2 v; i/ _4 o1 {eval是对Bash Shell命令行处理规则的灵活应用,进而构造"智能"命令实现复杂的功能。
) O( g" Z7 r% k8 K2 W上面提及的命令是eval其中一个很普通的应用,它重复了1次命令行参数传递过程,纯粹地执行命令的命令。
4 A. ^; N7 r' u) J" S4 ~" a/ ^$ }6 o其实它是bash的难点,是高级bash程序员的必修之技。
# A1 W( \6 z6 V. V2 V; t5 O. \ |