一乐电子

一乐电子百科

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

QQ登录

只需一步,快速开始

快捷登录

手机号码,快捷登录

搜索
查看: 2858|回复: 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

- L% x2 i7 p: `% [2 s  |
: O" M' T$ e0 x- O1 B# [* C

1 e6 L& q+ `! i$ ]4 H$ w5 E+ U$ N/ g  U2 C5 ?& X* w4 c1 `: i$ C
 楼主| 发表于 2017-2-22 15:31 | 显示全部楼层
功能说明:重新运算求出参数的内容。
. y/ L! ?7 d! G; X# T; `


8 ]% \" Y1 F4 T& e语  法eval [参数]
5 J2 Q' K' m  i9 }: |, b) o2 J5 p8 m
补充说明:eval可读取一连串的参数,然后再依参数本身的特性来执行。4 t( Z4 w  g* S9 g7 W/ A
2 s9 z9 B+ j# I2 `8 o5 Y
参  数:参数不限数目,彼此之间用分号分开。


7 S. ~" x9 q6 [: c+ d+ R" G
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 $#)"
0 k6 \7 o  _/ M

shell 也提供了 eval 命令,如同熟悉的其他脚本语言,会将它的参数做为命令执行,初看会疑惑为什么shell要提供两种动态执行命令字串的机制,但是经过仔细分析,才发现shell的eval同其他语言有很大区别。5 I& g3 z8 ?- K; o
/ q2 N5 o3 G; F9 m* I1 r
1.shell 中的函数虽然可以通过return 返回,但是这里的return 相当于 exit,只能是个状态值用于测试,而不能像其它语言一样返回复杂的结果,其处理结果只能通过输出到标准输出经过 `` ,$()取得。
4 V+ e: e3 Z9 s* _4 _: [0 ^% T' _- {/ I" q% a
2.shell 中的 eval
% J+ C; p: P5 v2 u" O9 L
- u/ w, H) r/ i8 f  j- T    2.1 不能获得函数处理结果 ,如1所说,所有命令,函数的处理结果只能通过 ``来获得,那么其它语言中利用eval来获得动态生成代码执行后的输出变得不可能。! I4 h6 T# r; W* ~
9 Z$ E" p' x# H
    2.2 eval 嵌套无意义 ,在其他语言中可以通过 eval(eval("code")),来执行(执行动态生成的code的返回),而由于shell 中 eval 将后面的eval命令简单当作命令字符串执行,失去了嵌套作用,嵌套被命令替换取代。

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

eval的作用是再次执行命令行处理,也就是说,对一个命令行,执行两次命令行处理。这个命令要用好,就要费一定的功夫。我举两个例子,抛砖引玉。
, L$ W& x: i* S5 }  {% d( C# e0 l8 G
1、例子1:用eval技巧实现shell的控制结构for( d5 C( S  H" p4 q+ {' [
6 G7 P7 F( X4 t7 ^  o% [! ]
用eval技巧实现shell的控制结构for。  f( O0 a4 D: q6 K2 p7 ^) `

2 ~0 ^3 v5 g7 d, K  T5 y[root@home root]# cat myscript1
2 `. Z( M# X2 o$ E+ H
' Q( P$ ?$ ~  q! \QUOTE:
) |7 ]4 `4 o& E4 a- H#!/bin/sh
/ P6 l- ^  u& d+ k. Y+ Y* u, u, wevalit(){2 `* p, [1 |: e7 G, \. X- S
        if [ $cnt = 1 ];then
- j3 y5 m$ D( D! t+ ]                eval $@
% O! H' E$ V1 s: h9 P                return8 b5 u7 ^9 E$ T$ e# a
        else
4 J4 m- Z- ~8 l+ ^9 l4 }3 I                let cnt="cnt-1"9 r" R$ s- u9 p& E. H- ~
                evalit $@% U& R$ h; Y" F( i& O
        fi
/ C6 W3 Q" w6 n% r        eval $@* H% N# `- p, _; R2 F  {2 b
}2 {1 Y9 x0 e9 H' o0 Y" O2 H; D- A
cnt=$1* C2 V; E9 D) J! m
echo $cnt | egrep "^[1-9][0-9]*$" >/dev/null) F: }# u4 ^: e
if [ $? -eq 0 ]; then
3 H3 c) D# A' z% K' B        shift
8 }3 {3 O  q) A" o        evalit $@
) [+ R1 o$ f9 j* u  O. Jelse5 Y1 W/ @) ^3 w8 f1 Y9 t+ e
        echo 'ERROR!!! Check your input!'' X/ K  V/ {" V; Z5 ]+ j
fi; k8 ^! x) S, W: e
[root@home root]# ./myscript1 3 hostname" r2 D! n: A1 h; A. ~' ^
home' O0 s. w+ l& H) Q
home
3 o# @% |7 o  h4 ?& L, ]home
- A2 s' g! {. v[root@home root]# ./myscript1 5 id |cut -f1 -d' '
/ @  {' i. |/ |; T8 o/ l# H. I6 j" cuid=0(root)
% `- a: T; J( q" Q  V- f) puid=0(root)
# q/ l4 g; N; kuid=0(root)% Y% Z* e$ q) ~% _% E
uid=0(root)
* p/ x' n" F- h, s- \2 auid=0(root)" q* Y3 d; ^* f6 j- M0 N
注意:bash里有两个很特殊的变量,它们保存了参数列表。
/ D& n% i& L7 {/ w+ U5 s" B( N1 {7 [. X$ O4 \. K! H8 r
$*,保存了以$IFS指定的分割符所分割的字符串组。* A' N6 |" t& c9 ]( F1 ?4 r  }
$@,原样保存了参数列表,也就是"$1""$2"...
4 N2 E& O4 D9 f9 W
2 a: a2 ?( M6 q7 ^, S" u: W这里我使用了函数递归以及eval实现了for结构。# d. r4 y( n) k8 o
当执行eval $@时,它经历了步骤如下:: T) p1 \4 l3 Z6 T7 B- _
第1步,分割成eval $@
+ x( X3 a7 {. M) t7 S. o) z1 ]第6步,扩展$@为hostname
, a1 z5 k, j" M" _' k第11步,找到内置命令eval
' F6 s  s) l; B1 ^, r( a1 A# G重复一次命令行处理,第11步,找到hostname命令,执行。
5 M- K9 p/ O, W& ^' ~
: l5 K& o3 p/ R% [# D注意:也许有人想当然地认为,何必用eval呢?直接$@来执行命令就可以了嘛。" v9 E3 F" x' L. ^# W" z
; @  v4 t3 Z+ r* _) T/ M) S; J# q
例子2:一个典型错误的例子% l8 O) U  Z3 }$ i4 @$ i  q

6 }( N! a: x( ?' t8 L& h错误!这里给个典型的例子大家看看。1 }/ c& [& Y5 o/ b
# u+ R- f; |6 m, b
- Q. G9 ?4 H+ C
[root@home root]# a="id | cut -f1 -d' '"
9 p4 u8 X: h  a2 E9 j$ K' d[root@home root]# $a3 f. V: ]# Y% t
id:无效选项 #  f8 h8 S% N/ ~( X9 G* U- x' q. o2 A
请尝试执行‘id # help’来获取更多信息。
6 s: W8 ^# s: E8 K6 H: E+ D[root@home root]# eval $a
1 V9 P4 b' j8 f- K3 T1 fuid=0(root): r$ A1 W1 Q: q$ u/ N( C$ ?
% l* }6 ~# E  I2 v' }) G( {! q
如果命令行复杂的话(包括管道或者其他字符),直接执行$a字符串的内容就会出错。分析如下。
) O/ ^/ Q; i2 a% v$a的处理位于第6步──参数扩展,也就是说,跳过了管道分析,于是"|", "cut", "-f1", "-d"都变成了id命令的参数,当然就出错啦。
; @! T$ z# k/ ^* f; E# l3 ]8 a但使用了eval,它把第一遍命令行处理所得的"id", "|", "cut", "-f1", "-d"这些字符串再次进行命令行处理,这次就能正确分析其中的管道了。& i9 A' a7 E" N1 l  n' w' B6 r
% R2 x/ t' m) Q2 X8 q9 X, y
总而言之:要保证你的命令或脚本设计能正确通过命令行处理,跳过任意一步,都可能造成意料外的错误!
' Z& P) @9 |- c5 J' x/ q6 o/ [  M" R1 h, c. H; S6 H
例子3:设置系统的ls色彩显示- C( o* M4 n5 L. D2 X* [3 v

4 y6 _: C* j6 l0 q' s
4 U' `4 A. E4 j( g8 Z/ y: Qeval $(dircolors -b /etc/dircolors)  e5 M; T% {) E6 |  V3 N, v! ^

, L" R+ ]0 ~! m9 |eval语句通知shell接受eval参数,并再次通过命令行处理的所有步骤运行它们。
& g, u, t. e, C* [+ H它使你可以编写脚本随意创建命令字符串,然后把它们传递给shell执行;! ^" P7 u' x' O3 E
$()是命令替换,返回命令的输出字符串。
) I3 |  d. x# H  p其中dircolors命令根据/etc/dircolors配置文件生成设置环境变量LS_COLORS的bash代码,内容如下
/ ?9 I0 I& H! A) f/ X1 g7 z. a# F% v+ v; t) i- {& p+ n" V8 \/ }
[root@localhost root]# dircolors -b > tmp
) ^# x  K5 k$ _8 M6 V% I& c: J[root@localhost root]# cat tmp
% O2 j, b6 i: c" F) i) V3 rLS_COLORS='no=00:fi=00:di=01;34:ln=01; ......0 E2 W' M- A4 U6 f/ f
export LS_COLORS
3 m. ^' H' L7 d#这里我没有指定配置文件,所以dircolors按预置数据库生成代码。
8 t0 o0 p; S9 g  k其输出被eval命令传递给shell执行。
/ a3 A9 X8 Y: ]/ Z! e' l$ O: x( _8 s: x6 Z) J* @* z, z, W' b
eval是对Bash Shell命令行处理规则的灵活应用,进而构造"智能"命令实现复杂的功能。
9 g# w. S) O5 Y" A上面提及的命令是eval其中一个很普通的应用,它重复了1次命令行参数传递过程,纯粹地执行命令的命令。
0 F8 Y' Y3 L7 ^3 R其实它是bash的难点,是高级bash程序员的必修之技。


8 f, B: s3 K8 O( X5 Q8 k  t

本版积分规则

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

GMT+8, 2024-4-28 15:26 , Processed in 0.052103 second(s), 24 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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