一乐电子

一乐电子百科

 找回密码
 请使用微信账号登录和注册会员

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 2828|回复: 1
收起左侧

linux命令eval的用法

[复制链接]
发表于 2017-2-22 15:24 | 显示全部楼层 |阅读模式

1. eval command-line

其中commandline是在终端上键入的一条普通命令行。然而当在它前面放上eval时,其结果是shell在执行命令行之前扫描它两次。如:

pipe="|"

eval ls $pipe wc -l

shell1次扫描命令行时,它替换出pipe的值|,接着eval使它再次扫描命令行,这时shell把|作为管道符号了。

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

2. eval echo \$$# 取得最后一个参数

如:cat last

eval echo \$$#

./last one two three four

four

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

3.以下示意如何用eval命令创建指向变量的“指针”:

x=100

ptrx=x

eval echo \$$ptrx 指向ptrx,用这里的方法可以理解b中的例子

100 打印100

eval $ptrx=50 50存到ptrx指向的变量中。

echo $x

50 打印50


' @" d# q% {: v9 F0 d6 }" k1 U- A1 U4 w% m$ P9 O( a: U& T: x8 B

8 [7 I" |. c, v3 n( A% w
+ X  n# o% R& |6 ?: ^, s+ M1 H- M
 楼主| 发表于 2017-2-22 15:31 | 显示全部楼层
功能说明:重新运算求出参数的内容。
( Q4 P; ~4 w: F$ B6 t. d


( S7 U% l3 R3 z0 \3 N# p1 ^语  法eval [参数]
; P( E9 R5 a& |! b1 O4 a
2 J* S" M. {8 o* @6 g0 S补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行。  B. o7 e7 y- j' u

9 z8 g( D- Y! o% Y- }参  数:参数不限数目,彼此之间用分号分开。


; y% [7 \8 {# `' \% c  U/ a
1.eval命令将会首先扫描命令行进行所有的替换,憨厚再执行命令。该命令使用于那些一次扫描无法实现其功能的变量。该命令对变量进行两次扫描。这些需要进行两次扫描的变量有时候被称为复杂变量。
2.eval也可以用于回显简单变量,不一定时复杂变量。
NAME=ZONE
eval echo $NAME等价于echo $NAME
3.两次扫描
test.txt内容:hello shell world!
myfile="cat test.txt"
(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 M% M( f# g6 I1 s0 h/ c

shell 也提供了 eval 命令,如同熟悉的其他脚本语言,会将它的参数做为命令执行,初看会疑惑为什么shell要提供两种动态执行命令字串的机制,但是经过仔细分析,才发现shell的eval同其他语言有很大区别。
6 x% U  [+ F" \& P9 O/ G$ k5 i5 C3 c# @+ [" j
1.shell 中的函数虽然可以通过return 返回,但是这里的return 相当于 exit,只能是个状态值用于测试,而不能像其它语言一样返回复杂的结果,其处理结果只能通过输出到标准输出经过 `` ,$()取得。7 f0 b( `( _' u( Z- ?% h+ b# S
! v; ~- O- a* c( Z* v) S. r* W7 @
2.shell 中的 eval
& I" R& j$ w4 N0 b$ M7 h# R$ {8 B) h: w5 T( x9 b8 P1 R8 a9 J
    2.1 不能获得函数处理结果 ,如1所说,所有命令,函数的处理结果只能通过 ``来获得,那么其它语言中利用eval来获得动态生成代码执行后的输出变得不可能。
2 s0 o/ Y7 x: u+ \0 X3 v  O5 y1 r$ J: e1 V) P* z- ?; o3 E
    2.2 eval 嵌套无意义 ,在其他语言中可以通过 eval(eval("code")),来执行(执行动态生成的code的返回),而由于shell 中 eval 将后面的eval命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。

扩展阅读:eval命令使用示例详解 资料整理www.linuxso.com

eval的作用是再次执行命令行处理,也就是说,对一个命令行,执行两次命令行处理。这个命令要用好,就要费一定的功夫。我举两个例子,抛砖引玉。2 F. ]9 M' @7 l, z

5 c: N+ I' N7 B) ?' P1、例子1:用eval技巧实现shell的控制结构for# E' R- g: n/ m. f
  f7 [. r+ S# j! [+ G5 n
用eval技巧实现shell的控制结构for。5 q/ {. @8 T5 y9 X( {' w0 b; s

: X( R, h+ |* _7 @% Q. l[root@home root]# cat myscript15 h* e, u0 _. R+ n% `1 e; c
0 ~; d' T( ]* k8 Q. X
QUOTE:! f! E- P( x( l7 H; e. g4 r
#!/bin/sh
8 D' u, I/ [+ P9 R( _$ ?evalit(){
+ h" x" y$ f0 @. H9 a& Q        if [ $cnt = 1 ];then
' r. G# z% U) n$ C2 c5 y                eval $@
' t# ?2 ~7 v. c2 A& d) y1 e3 A2 ~/ i                return
& d4 ?; ?0 u# m' i& S        else
* \9 g# U( l8 F- y: \+ n+ R8 J                let cnt="cnt-1"
* J+ L  R9 k+ ~  z9 L* V                evalit $@
, \6 v. D7 I/ W6 |) ?# Y        fi
7 {; B0 A, S5 F, M1 E4 S+ O        eval $@
  ~1 e+ e$ F1 J+ k! C7 b}
6 D# _' e6 w- h* p- e, n) {& x( Scnt=$1
4 p  w9 T2 F* u  b% X4 t) y9 fecho $cnt | egrep "^[1-9][0-9]*$" >/dev/null7 o0 {( c0 j  [' [- g7 V
if [ $? -eq 0 ]; then
5 ~  R3 e3 ?4 j; }7 z" G        shift
. d( p; q# W, Y/ M        evalit $@
1 p. t& P3 x* q# Jelse- A6 d2 m1 K& B/ J' f
        echo 'ERROR!!! Check your input!'4 }, F# P0 k$ A5 Q1 H
fi# _( `& j6 k  q3 [: n0 m
[root@home root]# ./myscript1 3 hostname
0 V  D6 H- ^. J: T, r. a: _7 Mhome
  |4 F4 X+ g3 `" ~7 Z9 [$ \home
& E+ B& d5 [0 H2 Z! F, hhome
  S! ~" U$ @2 l; L+ q4 u, @; _[root@home root]# ./myscript1 5 id |cut -f1 -d' '! C6 e. b, u0 m
uid=0(root)
8 B7 G) I% M0 V: Muid=0(root)
. f# u' v' g4 N3 O* `) c/ fuid=0(root)3 g$ f0 W( [- _( H( r
uid=0(root)
/ i) t: n5 W8 a% }1 [# S$ zuid=0(root)
4 y+ V- w/ S6 F/ \& o5 p* f( O注意:bash里有两个很特殊的变量,它们保存了参数列表。+ R$ }. [: z7 _9 l% Q
4 g5 h4 B" z5 Y/ \
$*,保存了以$IFS指定的分割符所分割的字符串组。
* o" X- i+ U% d1 z* g$@,原样保存了参数列表,也就是"$1""$2"...
  \+ S7 s+ j- u: w4 p5 l: A0 F3 u+ m% O
这里我使用了函数递归以及eval实现了for结构。
$ O8 x' a& T5 m3 V  _$ X% P当执行eval $@时,它经历了步骤如下:
! B% a! a/ a. b第1步,分割成eval $@0 q  [4 a' g" y. U0 U
第6步,扩展$@为hostname
4 V, m, x* G4 y! O3 j第11步,找到内置命令eval3 c5 l; ?7 N# T
重复一次命令行处理,第11步,找到hostname命令,执行。
0 O- s: Q. r5 V5 A# l, a3 {9 `8 I1 z) _0 z5 b( |
注意:也许有人想当然地认为,何必用eval呢?直接$@来执行命令就可以了嘛。
  Q. ]* o) V; z9 B/ Q( u
* z$ \, J4 B1 \3 Z例子2:一个典型错误的例子
* }6 m+ Q( I- g/ O( s9 I& f, x
: A' r5 z7 U3 v- ^0 b" L错误!这里给个典型的例子大家看看。7 P' z# |/ F: A
  h7 c6 ~  G# K

2 a4 b$ l6 e: j. c% s7 H) `[root@home root]# a="id | cut -f1 -d' '"
# B. z! y: z/ ?, w0 ~' \[root@home root]# $a8 s2 g& E* n9 {/ o* b* q
id:无效选项 #  f
, n$ ?5 R2 S& X9 c( l3 i请尝试执行‘id # help’来获取更多信息。
# H, |. q- y  S- V[root@home root]# eval $a& C7 p: d2 e- a  R; V; V' N
uid=0(root)) D8 K% ]; N% I: H0 |
# A" m8 [. u, ?: K
如果命令行复杂的话(包括管道或者其他字符),直接执行$a字符串的内容就会出错。分析如下。
5 M6 n1 }- N% ~; ^) P4 K4 G$a的处理位于第6步──参数扩展,也就是说,跳过了管道分析,于是"|", "cut", "-f1", "-d"都变成了id命令的参数,当然就出错啦。/ u& ]: Y3 f! ]! @
但使用了eval,它把第一遍命令行处理所得的"id", "|", "cut", "-f1", "-d"这些字符串再次进行命令行处理,这次就能正确分析其中的管道了。
. q. Z: Y9 @; [$ F
1 j+ t5 \: m. z8 f. E, M- b$ M总而言之:要保证你的命令或脚本设计能正确通过命令行处理,跳过任意一步,都可能造成意料外的错误!
3 Q9 y' x# a: |2 g+ [
+ {. Q0 B+ H) _: c+ t* v例子3:设置系统的ls色彩显示
) W0 |( ^( q! _' R7 R" J& h2 s
6 |2 J) V7 M2 N# @1 J( Q  @) d* b$ u4 `6 O9 D& A% W
eval $(dircolors -b /etc/dircolors)# O8 x, Q0 @. T9 E( V  }. W; ^
; c: N; K5 p: O1 n0 j0 A) G  v, ~2 H7 V% O
eval语句通知shell接受eval参数,并再次通过命令行处理的所有步骤运行它们。. I2 [) m/ r6 v
它使你可以编写脚本随意创建命令字符串,然后把它们传递给shell执行;
: R! b2 E9 g7 A: [: e$ {$()是命令替换,返回命令的输出字符串。
* e1 w8 p0 n9 y  H3 _其中dircolors命令根据/etc/dircolors配置文件生成设置环境变量LS_COLORS的bash代码,内容如下
  C1 A, m: Y/ K- ]
3 U, t, D$ I  R% |& S[root@localhost root]# dircolors -b > tmp
) B0 `) {; D0 t6 G[root@localhost root]# cat tmp( I% t$ \/ g7 G7 b
LS_COLORS='no=00:fi=00:di=01;34:ln=01; ......# Z4 l7 K+ B. z$ J) n+ j+ }
export LS_COLORS3 X  ^/ r0 o, X, \) W
#这里我没有指定配置文件,所以dircolors按预置数据库生成代码。
  f4 l$ K' d6 A' O* m+ F& l/ v其输出被eval命令传递给shell执行。* ?$ G' o+ l+ C, w% w7 q
$ r. B$ G7 h1 c7 i) ^
eval是对Bash Shell命令行处理规则的灵活应用,进而构造"智能"命令实现复杂的功能。1 s+ e8 g  v+ z  M2 w" M, M. |
上面提及的命令是eval其中一个很普通的应用,它重复了1次命令行参数传递过程,纯粹地执行命令的命令。/ r. M" h5 {: f; Y5 ^+ f: J9 w
其实它是bash的难点,是高级bash程序员的必修之技。

/ s. `# A9 w% N7 v$ E

本版积分规则

QQ|一淘宝店|手机版|商店|电子DIY套件|一乐电子 ( 粤ICP备09076165号 ) 公安备案粤公网安备 44522102000183号

GMT+8, 2024-4-20 19:18 , Processed in 0.053070 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表