功能说明:重新运算求出参数的内容。9 `6 B! {1 y! P1 c9 B0 d5 c! y
1 n0 J- N# L" l3 t( I% ~* o# ~语 法:eval [参数]4 d4 z4 B$ l6 B. Z$ n- P
- Q. G9 q/ Q$ R2 C" _补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行。
9 c. ]! X3 Z8 o% ?9 v6 k! U9 \0 X% o% d8 f% ?, N/ v! x
参 数:参数不限数目,彼此之间用分号分开。
$ X5 k4 c0 g0 s1.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 $#)" 1 z/ ~" a$ A* R2 z7 a. d: i
shell 也提供了 eval 命令,如同熟悉的其他脚本语言,会将它的参数做为命令执行,初看会疑惑为什么shell要提供两种动态执行命令字串的机制,但是经过仔细分析,才发现shell的eval同其他语言有很大区别。
0 H9 P. Z2 K2 ~) K o# d% C
2 F% t9 E3 B W8 l* M3 A F: ?1.shell 中的函数虽然可以通过return 返回,但是这里的return 相当于 exit,只能是个状态值用于测试,而不能像其它语言一样返回复杂的结果,其处理结果只能通过输出到标准输出经过 `` ,$()取得。0 a1 W3 \$ |& n
2 N" J" l( K8 ]7 j5 A( C2.shell 中的 eval/ G" H" H9 G, X& n6 a1 {, _' ~+ X
/ v# q k+ M5 d/ k3 j$ W1 B. @
2.1 不能获得函数处理结果 ,如1所说,所有命令,函数的处理结果只能通过 ``来获得,那么其它语言中利用eval来获得动态生成代码执行后的输出变得不可能。
, I* L0 i! j3 G, @
6 q: K. Z! n# ^1 ?( ^2 {6 q* @ 2.2 eval 嵌套无意义 ,在其他语言中可以通过 eval(eval("code")),来执行(执行动态生成的code的返回),而由于shell 中 eval 将后面的eval命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。 扩展阅读:eval命令使用示例详解 资料整理www.linuxso.com eval的作用是再次执行命令行处理,也就是说,对一个命令行,执行两次命令行处理。这个命令要用好,就要费一定的功夫。我举两个例子,抛砖引玉。& {$ {5 Y0 y; _1 E+ t" |
0 }5 @- N( W# z5 p
1、例子1:用eval技巧实现shell的控制结构for3 f# P, X; d" E0 U( i* V7 R
% O' g; P+ U+ z用eval技巧实现shell的控制结构for。' W3 n( j9 f& g) u
* u5 a) F; y) X* x/ d m [4 \[root@home root]# cat myscript1
' i7 M% w# y: {) [) t( Z1 e4 \8 v1 o) W
QUOTE:
- f3 e8 M* R' a5 _! U% W6 c#!/bin/sh
" R8 m5 W) s+ v* Gevalit(){' u+ `, Y2 f, j- ~0 L7 L4 Q( |. p
if [ $cnt = 1 ];then3 F! k: e' l* K* T ?/ E; ?
eval $@
4 A" |6 @' J8 e8 [) [" Z7 b( V" W return% V( e) p! Q/ k' j) l9 ^
else* O5 L9 L2 d. A+ M s( @- z
let cnt="cnt-1"$ k' C9 d8 O2 Q) M
evalit $@' c q% y! d; z2 U; @
fi
. m7 s2 a1 h. @' Q& m eval $@
% E5 \+ _8 n2 ^8 { N+ W2 }}, B9 T9 w6 n$ X' f
cnt=$13 G. c' j. N1 K5 P7 |; u" @1 \
echo $cnt | egrep "^[1-9][0-9]*$" >/dev/null$ z# i+ k4 t: g. }4 V# ?
if [ $? -eq 0 ]; then5 j5 Y. _0 N4 }' y
shift
, b0 f% `: X0 f! \: D- n% {* H evalit $@
8 X3 g @ k# pelse
; v) m; l$ X+ m echo 'ERROR!!! Check your input!'
+ w; F: y- H' h y+ r x% [fi
. t o( p/ i; R, j" ~2 \7 x[root@home root]# ./myscript1 3 hostname
" _9 f) w1 [( D! v3 h% shome! \" U- u. O: i% v2 u! o ^' B
home
: O0 U' L5 r; `" F9 qhome5 k' N; Q1 I+ D( Q
[root@home root]# ./myscript1 5 id |cut -f1 -d' '' K2 G& A+ H7 s6 J2 J
uid=0(root)
: r6 i1 v: d# U" u7 Muid=0(root). o# g' [5 G7 `3 M9 s$ `9 K
uid=0(root)
O5 }" n, \' t! y1 G4 L: Vuid=0(root)
/ b1 Z1 T: g& `7 ?3 q6 zuid=0(root)
; u, I% G% S8 J* L/ i2 O D$ l* Y, ?注意:bash里有两个很特殊的变量,它们保存了参数列表。4 Q' p4 { j7 M* y; N1 R9 A" u R4 R* V5 D
' p7 U6 W- N* l3 n4 G$*,保存了以$IFS指定的分割符所分割的字符串组。8 \* h: x9 E8 }; Q: X% n
$@,原样保存了参数列表,也就是"$1""$2"...
0 l% V( _! V8 m1 y! N5 G6 f0 U# H( _/ Z* t6 H
这里我使用了函数递归以及eval实现了for结构。4 A; }: x3 g# P) ^4 U# H
当执行eval $@时,它经历了步骤如下:$ E( O% x; u7 g' U: h
第1步,分割成eval $@" A# u4 J& {6 c
第6步,扩展$@为hostname$ m( B2 U1 P9 v! J
第11步,找到内置命令eval
) E5 z+ V5 T) y$ K6 R# |/ C- g; \重复一次命令行处理,第11步,找到hostname命令,执行。! V' I4 R2 S! \3 s$ y. B. U0 U7 z- c
: e: \/ R. y( C
注意:也许有人想当然地认为,何必用eval呢?直接$@来执行命令就可以了嘛。
, Z: _2 U2 d3 E, y
) S( z$ `, I1 N6 a( q ^9 f2 b5 s例子2:一个典型错误的例子( r3 ~8 Z! m9 }, i& f
7 C" n- w6 O% a
错误!这里给个典型的例子大家看看。
. d' k; R2 w/ m0 A/ d. q+ h
' z! ]! e' S" s/ g1 W% [1 ?& b
% |/ Y3 T( j1 y/ w, v. s[root@home root]# a="id | cut -f1 -d' '"4 r# m) I+ E u9 L n% P6 [! G$ i
[root@home root]# $a+ ^3 l3 G& P( `
id:无效选项 # f+ U6 A, V, N8 H5 K1 i2 o' g
请尝试执行‘id # help’来获取更多信息。$ N. |3 y8 @. _5 T. D
[root@home root]# eval $a, m2 @$ _" X# B- o7 T( n
uid=0(root)8 I: D- e& k0 G G) k3 g
" b' b6 Z. Z7 v
如果命令行复杂的话(包括管道或者其他字符),直接执行$a字符串的内容就会出错。分析如下。
3 L3 K. h' g/ @7 o7 l$a的处理位于第6步──参数扩展,也就是说,跳过了管道分析,于是"|", "cut", "-f1", "-d"都变成了id命令的参数,当然就出错啦。
0 v1 o! T, z* u _) f但使用了eval,它把第一遍命令行处理所得的"id", "|", "cut", "-f1", "-d"这些字符串再次进行命令行处理,这次就能正确分析其中的管道了。
' ]9 ]) s! p# L
! A- ?, {7 u( p& y K D/ [6 _5 x总而言之:要保证你的命令或脚本设计能正确通过命令行处理,跳过任意一步,都可能造成意料外的错误!
9 K+ A' t% x& V+ y
6 [- R0 T, `3 O2 G例子3:设置系统的ls色彩显示- K! K! t l4 |% w0 E) k% K8 J! l1 J
- E8 O% R9 S3 ^5 s( X7 ^+ R' T- M B" A; t$ Y- f8 s, k
eval $(dircolors -b /etc/dircolors)
: L% n7 P" ]' _4 f" T c/ `
7 w4 R' C' L6 x0 n1 b* I7 n$ c. peval语句通知shell接受eval参数,并再次通过命令行处理的所有步骤运行它们。+ n1 D. }. c) h7 I/ q& p% Q
它使你可以编写脚本随意创建命令字符串,然后把它们传递给shell执行;
! ~# w( V; I( b' P$ W$()是命令替换,返回命令的输出字符串。" z: k1 N* @; z# h: `# C4 J
其中dircolors命令根据/etc/dircolors配置文件生成设置环境变量LS_COLORS的bash代码,内容如下
8 h( H3 n8 H% x; a2 B2 b
/ ^6 m( W1 q6 q[root@localhost root]# dircolors -b > tmp/ N9 b) r/ ?( S- x5 J/ a
[root@localhost root]# cat tmp- @" e" ?6 p# j4 t; l6 E9 S
LS_COLORS='no=00:fi=00:di=01;34:ln=01; ......
1 j$ `- s9 P( sexport LS_COLORS
4 K6 A$ S, h% p! r+ f6 K2 N$ [#这里我没有指定配置文件,所以dircolors按预置数据库生成代码。- l v1 [8 A! f y b
其输出被eval命令传递给shell执行。' _6 z) J1 S% O+ c3 f
( N$ O5 d: n4 f$ H [eval是对Bash Shell命令行处理规则的灵活应用,进而构造"智能"命令实现复杂的功能。
- h% _* @! V) z$ N4 `' u上面提及的命令是eval其中一个很普通的应用,它重复了1次命令行参数传递过程,纯粹地执行命令的命令。$ E* R) x0 m6 M: C$ P
其实它是bash的难点,是高级bash程序员的必修之技。 $ L4 D5 o! J: N2 Y9 \+ d2 u
|