- 浏览: 1184214 次
文章分类
最新评论
-
你不懂的温柔:
楼主是好人
H264学习指南 -
18215361994:
谢谢,您能够给我们总结这么多,我们会为了自己的目标加油的, ...
新东方老师谈如何学英语 -
beyondsoros_king:
testerlixieinstein 写道结果就是11,编译不 ...
揪心的JAVA面试题 -
buptwhisper:
其实这个也好弄清楚的,你在每一个可能的地方打上断点,然后deb ...
揪心的JAVA面试题 -
wmswu:
这种类型的面试题 还真不少啊.......
揪心的JAVA面试题
Unix/Linux 平台任务的自动化
转载自:水木清华BBS
本章要点:
本章介绍用来替代shell脚本的工具,如TCL和perl。
本章具体包括以下内容。
TCL/expect的使用
awk语言的基本知识
perl语言的基本知识
11.1TCL和expect
TCL是一种类似shell脚本的语言,你可以使用它来完成许多操作。不过,我介绍它的
主要原因是expect是从它发展出来的。如果你想要写一个能够自动处理输入输出的脚本
(如向用户提问并且验证密码)又不想面对C或者Perl,那么expect是你的唯一选择。
11.1.1TCL语言
要使用TCL,你必须先安装这个程序:
%rpm-qtcl
tcl-8.0.5-30
TCL语言可以用交互式或者脚本的方式执行,要使用交互式的TCL环境,只要输入
$tclsh
%
出现的"%"符号是TCL的提示符,然后就可以使用TCL命令的。
如果你要使用脚本方式的TCL,首先把你的脚本写成一个文本文件,例如test.tcl,然
后执行
$tclshtest.tcl
在tcl脚本中,每一行或者是一个命令行,或者是一个注释。注释行必须以#符号开头
,而命令行最好以分号结束,虽然不一定要这样做,但是这样做可以免去不少麻烦。
变量
在tcl中,有两种基本类型的变量,即标量和数组。标量就是一般的数字或者字符串变
量,可以用set语句定义同时赋值:
%seti1
1
字符串应该用引号括起来:
%setstr"test"
'test'
要输出一个标量的内容,使用put语句:
%puts$str
test
$用来说明str是一个变量。puts函数在标准输出显示变量的内容。
数组也可以用set语句定义,实际上,tcl中建立数组只是单个建立数组的元素。例如
,
%setarr(1)0
0
%setarr(2)1
1
这样就建立了一个两个元素的数组arr。在TCL中,不存在相当于数组边界这样的东西
,例如
%setarr(100)to
to
这时数组中实际只存在arr(1),arr(2)和arr(100),这是和C语言不同的地方。用arr
aysize命令可以返回数组的大小:
%arraysizearr
3
访问数组的方法和访问标两实际是一样的,例如:
%puts$arr(100)
to
可以用同样的方法创建多维数组。
要使用数组中的所有元素,需要使用一种特殊的便利方式。首先要启动startsearsh:
%arraystartsearcharr
s-1-arr
这里返回了一个搜索id,你可以把它传递给某个变量,因为以后还要使用它进行进一
步的搜索:
%setmy_id[arraystartsearcharr]
s-1-arr
现在my_id的内容是s-1-arr,然后,就可以搜索arr的内容了:
%arraynextelementarr$my_id
whi
这里的arraynextelement返回的是什么?可能有点出乎你的意料,是arr数组的下标
,再执行一次arraynextelement命令又会找出另外一个下标:
%arraynextelementarr$my_id
4
这样遍历下去,可以找出arr数组的所有下标,而知道下标之后,就可以用$arr(4)之
类的方式访问arr的内容了。当遍历完成之后,arraynextelement命令将简单地返回:
%arraynextelementarr$my_id
%
这时就可以停止遍历过程了,如果你想确认遍历是否完成,可以使用arrayanymore命
令:
%arrayanymorearr$my_id
0
返回0说明遍历已经完成。
串处理
TCL中可以进行一般的串处理过程,这可以使用string命令和append命令,append命令
将某个字符串加到另外一个字符串的后面:
%setstr1"test"
test
%setstr2"cookit"
cookit
%appendstr1$str2"andother"
testcookitandother
string命令可以执行字符串的比较,删除和查询,其格式是string[参数]string1
[string2]
参数可以是下面的命令之一:
compare按照字典顺序对字符串进行比较,根据相对关系返回-1,0或者+1。
first返回string2中第一次出现string1的位置,如果失败,返回-1。
last返回string2中最后一次出现string1的位置,如果失败,返回-1
trim从string1中删除开头和结尾的出现在string2中的字符
trimleft从string1中删除开头的出现在string2中的字符。
trimright从string1中删除结尾的出现在string2中的字符
下面几个用在string中的参数不需要string2变量:
length返回tring1的长度
tolower返回将string1全部小写化的串
toupper返回将string1全部大写化的串
运算
TCL的运算方式比较别扭,它使用expr命令作为计算符号,其用法类似C语言的+=和/=
,例如,
%setj[expr$i/5]
1
注意TCL会自动选择整数或者浮点计算:
%setl[expr$i/4.0]
1.25
%setl[expr$i/4]
1
在TCL里面可以使用+-*/和%作为基本运算符,另外通常还包括一些数学函数,如a
bs,sin,cos,exp和power(乘方)等等。
另外,还有一个起运算符作用的命令incr,它用来对变量加一:
%seti1
1
%incri
2
流程控制
tcl支持分支和循环。分支语句可以使用if和switch实现。if语句的和C语言类似,如
if{$x<0}{
sety10;
}
注意判断子句也需要使用花括号。
与C语言一样,tcl的if语句也可以使用else和elseif。
switch语句的用法有点类似这样:
switch$x{
0{sety10;}
10{sety100;}
20{sety400;}
}
与C的switch语句不同,每次只有符合分支值的子句才被执行。
循环命令主要由for,foreach和while构成,而且每一个都可以使用break和continue
子句。
for语句的格式有点类似这样:
for{seti0}{$i<10}{incri}{puts$i}
将会输出从1到9的整数。
如果用while循环,这个句子可以写成
while{$i<10}{
puts$i;
incri;
}
foreach是对于集合中的每一个元素执行一次命令,大致的命令格式是
foreach[变量]{集合}{
语句;
}
例如
%foreachj{135}{
put$j;
}
1
3
5
函数
如同在一般的编程语言里面一样,在tcl里面也可以定义函数,这是通过proc命令实现
的:
procmy_proc{i}{
puts$i;
}
这样就定义了一个名字叫proc的函数,它只是在终端显示输入变元的内容。
要使用这个函数,简单地输入它的名字:
%my_proc{5}
5
如果变元的数目是0,只要使用空的变元列表,例如procmy_proc{}{语句;}
尽管tcl还可以处理更复杂的过程,但是我们不再介绍了,例如文件的读写以及tk图形
语言,因为我们处理tcl的主要目标就是理解expect,对于更复杂的编程工作,我们建议
你使用perl。
11.1.2expect
expect是建立在tcl基础上的一个工具,它用来让一些需要交互的任务自动化地完成。
我们首先从一个简单的例子开始,如同在这一节一开始就提到的,我们想设置一个自动
的文件下载程序。
我们看一看这样的一个例子脚本:
#!/usr/bin/expect
spawnftp202.199.248.11
expect"Name"
send"ftp/r"
expect"Password:"
send"nothing/r"
expect"apply"
send"cd/pub/UNIX/Linux/remoteX/r"
expect"successful."
send"bin/r"
expect"settoI"
send"getexceed5.zip/r"
expect"complete."
send"quit/r"
这个是什么意思?呵呵,就是个自动下载程序。第一行说明这个程序应该调用/usr/b
in/expect去执行,然后的就是expect命令。
察看expect的手册页面(manexpect)可以得到一个很长的expect说明,可惜其中关于
expect的语法仍然介绍的不够。一般来说,expect主要用在需要自动执行人机交互的过
程中,例如fsck程序,这个程序会不断地提问"yes/no",像这样的命令就可以用expect
来完成。
spawn语句在expect脚本中用于启动一个新的进程,在我们的程序中,spawnftp202
.199.248.11就是去执行ftp程序,接下来,就是expect和send的指令对了。
每一对expect和send指令代表一个信息/回应。如果这样说不好理解的话,那么可以看
一看ftp的具体执行过程:
ftp202.199.248.11
Connectedto202.199.248.11.
220mail.asnc.edu.cnFTPserver(BeroFTPD1.3.3(3)SunFeb2015:52:49CST
2000.
Name(202.199.248.11:wanghy):
显然,一旦连接成功,服务器会返回一个Name(202.199.248.11:wanghy):的字符串来
要求客户给出用户名。expect语句简单地在返回信息中查询你给出的字符串,一旦成功
就执行下面的命令,现在,expect"Name"已经成功地找到了Name字符串,接下来可以
执行send命令了。
send命令比expect命令更简单,它简单地向标准输入提交你设定的字符串,现在设置
为send"ftp/r"表示等到登录信息之后就给出一个输入ftp回车,也就是标准的登录过
程。
下面的行与这些行完全一样,只是机械地等待服务器的回应,并且提交自己的输入。
要使用这个expect脚本,你只需要将它设置为可执行的属性,然后执行它,expect就
会执行你需要的服务。
由于expect是tcl的扩展,所以你在expect文件中可以象tcl脚本一样设置变量和程序
流程。
现在我们看一看我们还能够如何改进我们的expect脚本。ftp命令可能会失败,比如远
端的机器可能会无法提供服务,或者在启动ftp命令时本地机器发生问题。为了处理这一
类的问题,我们可以使用expect的timeout选项来设置超时的话expect脚本自动退出:
#!/usr/bin/expect
spawnftp202.199.248.11
expect{
timeoutexit
Connect
}
………………
注意这里面使用的花括号。它的含义是使用一组并列表达式。使用并列表达式的主要
原因是这样:如果使用下面的指令对:
expecttimeout
exit
那么由于expect脚本是顺序执行的,那么当程序执行到这个expect的时候就会阻塞,
所以程序会一直等待到timeout然后退出。并列表达式则是相当于switch的行为,只要列
出的几项内容有一项得到满足,expect命令就得到满足,于是程序可以正常执行。上面
的脚本表示,如果连接ftp的时候发生了超时,那么就退出,否则,一旦发现Connect应
答,说明服务器已经正常了,那么就可以继续运行了。
我们可以看看用tcl能够对我们的expect脚本提供什么帮助。我们可以设置让expect脚
本不断地连接远端服务器的服务,直到正常建立连接开始,为此,我们可以把建立连接
的命令放在一个循环里面,并且根据回应的不同自动选择重新输入命令还是继续执行:
spawnftp
while{1}{
expect"ftp>"
send"o202.199.248.11/r"
expect{
"Connected"break
"refused"{sleep10};
}
}
这里使用了我们在tcl语言中讲到的while和break命令,熟悉C的读者应该很容易看出
它的行为:不断地等待ftp>提示符,在提示符下面发送连接远端服务器的命令,如果服
务器回应是refused(连接失败),就等待10秒钟,然后开始下一次循环;如果是Conne
cted,那么就跳出循环执行下面的命令。sleep是expect的一个标准命令,表示暂停若干
秒钟。
expect还支持许多更复杂的进程控制方式,如fork,disconnect等等,你可以从手册
页面中得到详细的信息。另外,各种tcl运算符和流程控制命令,包括tcl函数也可以使
用。
有些读者可能会问,如果expect执行的话是否控制台输入不能使用了,答案是否定的
。expect命令运行时,如果某个等待的信息没有得到,那么程序会阻塞在相应的expect
语句处,这时,你在键盘上输入的东西仍然可以正常地传递到程序中去,其实对于那些
expect处理的信息,原则上你输入的内容仍然有效,只是expect的反映太快,总是抢在
你的前面“输入”就是了。知道了这一点之后,你就可能写一个expect脚本,让expect
自动处理来自fscki的那些恶心的yes/no选项(我们介绍过,这些yes/no其实完全是多余
的,正常情况下你除了选择yes之外什么也干不了)。
缺省下,expect在标准输出(你的终端上)输出所有来自应用程序的回应信息,你可
以用下面的两个命令重定向这些信息:
log_file[文件名]
这个命令让expect在你设置的文件中记录输出信息。必须注意,这个选项并不影响控
制台输出信息,不过如果你通过crond设置expect脚本在半夜运行的话,你就确实可能需
要这个命令来记录各种信息了。例如:
log_fileexpect.log
log_user0/1
这个选项设置是否显示输出信息,设置为1时是缺省值,为0的话,expect将不产生任
何输出信息,或者说简单地过滤掉控制台输出。必须记住,如果你用log_user0关闭了
控制台输出,那么你同时也就关闭了对记录文件的输出。
这一点很让人困扰,如果你确实想要记录expect的输出却不想让它在控制台上制造垃
圾的话,你可以简单地把expect的输出重定向到/dev/null:
./test.exp>/dev/null
你可以象下面这样使用一对fork和disconnect命令。expect的disconnect命令将使得
相应的进程到后台执行,输入和输出被重定向到/dev/null:
if[fork]!=0exit
disconnect
fork命令会产生出一个子进程,而且它产生返回值,如果返回的是0,说明这是一个子
进程,如果不为0,那么是父进程。因此,执行了fork命令之后,父进程死亡而子进程被
disconnect命令放到后台执行。注意disconnect命令只能对子进程使用。
11.2awk和文件的处理
UNIX里面充斥着各种记录文件和类似的东西。对文本文件的处理是系统管理员每天重
要的工作,例如从系统记录中查找重要的内容,或者对某种程序的输出进行统计等等。
我们将介绍常用的一个处理程序,即gawk。
11.2.1grep和正则表达式
让我们首先从grep命令开始。这个命令大家应该很熟悉了,它用来在文件中查找一个
字符串。不过,实际上,grep的处理功能要强大和复杂的多。
grep命令的语法是
grep[模式][文件名]
如果没有给出文件名,就缺省使用标准输入。grep每次读取一行,并且和给出的模式
进行匹配,如果成功就把这一行会显,例如:(粗体的是我们输入的内容)
$greptest
close
testmyhand
testmyhand
grep的“模式”也称为正则表达式,可以由各种基本的正则表达式元素构成。正则表
达式元素主要包括下面几种:
字符串匹配任何字符串,例如greptest表示在标准输入中1
[...]封闭集中匹配一个字符,如:[abcde]可以匹配a,b,c,d,e
[^...]求补集中匹配一个字符,例如[^ABC]匹配
.匹配任意字符
/s空白符
/S非空白符
/d数字
/D非数字
/w字母或数字
/W非字母和数字
*匹配任何字符
上面的形式是grep中使用的基本正则表达式,另外,还可以使用egrep,egrep是grep
的一个扩展版本,支持下面这些扩展的正则字符串:
^匹配一行的开始
$匹配一行的结尾
()确定正则表达式求值顺序,和正常演算中的括号意思差不多。
(...|...|...)或,可选项之一进行匹配,例如:(abc|dev|ghi)可以匹配abc,dev,gh
i,而(ww|gg)do可以匹配wwdo或者ggdo。
+一次或多次模式
如:aba+匹配aba,abaa...不匹配ab
通常,我们有两种方法使用grep和egrep,一种是使用管道,例如我们应该熟悉的ps
ax|grepsendmail,另一种是直接在文件中搜索对应的字符串。
grep/egrep还可以在命令行使用开关,常用的开关包括:
-b在行前加上块号
-c统计匹配行的个数
-n在行前加上行号
-w将模式解释为字符串,所有正则表达式的控制命令失效
-x精确匹配
-r查询文件时包含子目录
举个例子来说,我们想在/var/log/httpd/access_log中查询所有不是来自本地(192
.168.0.1)的请求记录,可以执行:
grep–v"^192.168.0.1"/var/log/httpd/access_log
^用来让grep只在行首匹配。
在grep查询的时候可以使用通配符代表多个文件,例如,grepstart*-r将在当前目
录以及所有子目录的所有文件中查询start字符串。
11.2.2gawk的使用方法
gawk是awk的一个实现,awk是一种用来处理报告等文本文件的脚本语言。不过,我们
介绍这个产品的主要目标是用它来处理各种程序的记账文件。对于复杂的脚本,还是用
Perl比较合适。
gawk的主要功能是针对档案的每一行搜寻指定的模式。,每当找到一个匹配的模式
,gawk就会去执行你设定的动作。按照这个方式,gawk依此方式处理输入档案的每一
行直到输入档案结束。如果对于某个模式没有设置对应的动作,gawk将直接将这个行显
示出来。
为了使用gawk,你通常必须先写一个awk脚本,除非模式/动作非常简单,可以在一行
上完成。我们用一个例子来解释gawk的基本用法,首先产生一个目录列表文件:
ls–l/etc>list
现在list的内容有点像这样:
total2164
drwxr-xr-x3rootroot4096Feb1522:55CORBA
-rw-r--r--1rootroot2045Sep241999DIR_COLORS
-rw-r--r--1rootroot17Mar2519:59HOSTNAME
…………
现在我们选择一个最简单的例子,简单地查找所有属性是drwxr-xr-x的目录文件:
gawk'/drwxr-xr-x/{print$0}'list
将输出所有这样的目录。
这个例子看上去没有什么实际用处,因为用grep也可以做同样的动作,那么我们可以
看一看下面这个功能:
$gawk'$1=="-rwxr-xr-x"{sum=sum+$5}END{printsum}'list
15041
这个是什么意思?对于所有属性是755的文件,让gawk对第五栏的数字求和。第五栏我
们可以看到就是文件的长度,因此这个命令将显示所有属性为755的文件的总共的长度。
$n是gawk中非常重要的概念,它用来表示文本串的分栏。缺省的情况下,gawk将输入
字符串(从文件中读入的每一行)按照分割的空格分成若干个字段,每个字段作为一个
变量,例如有一行
mynameis3thtest
那么,在awk读入这一行之后,就产生了$1到$5变量,其中$1="my",$2="is",………
,最后$5="test"。另外还有一个特殊的变量$0,它表示整个输入行,也就是这个字符串
"mynameistest"。另外还有一个特殊的变量NF,它表示当前行的字段的个数,在现在
的情况下,NF应该等于5。
在某些特殊的情况下,你可能需要改变分割符的定义,这可以通过对FS赋值来完成,
例如FS=","将分割符定义为都号而不是缺省的空格。
在一般情况下,gawk可以从命令文件中获得模式/动作,命令文件的格式很简单,就是
直接将应该写在命令行上的模式/动作对写在文件里面,每个对构成一行,模式可以有两
种,一种是模式匹配,也就是我们在前面解释的正则表达式,如果使用正则表达式,那
么需要用两个/把它们夹在一起,例如/[A-Z]/表示正则表达式[A-Z]。
另一种模式是比较指令,比较指令可以用比较操作符和逻辑运算符来构成,常用的比
较操作符有:
==等于<=不大于~按照正则表达式匹配
<小于>=不小于!~按照正则表达式不匹配
>大于!=不等于
逻辑运算符有
&&和||或!非()括号
设定了模式后,就可以设置对应的动作了,在gawk中,动作必须用花括号括起来。ga
wk能完成的动作并不多,毕竟它是一种报告分析语言。一般情况下,只要熟悉print和p
rintf命令就足够了,print命令的格式非常简单:
printitem1,item2,…………
输出时,每个项目输出一栏,中间用空格分开。一个print后面不跟着任何变量会导致
gawk显示当前的输入行($0)。如果要输出一个字符串,使用引号把它括起来,特别是
如果要输出一个空行,使用print""。这里是一个例子,它将list文件的头两栏输出:
gawk'{print$1,$2}'list
由于输入的文本文件内容有多行,你在命令栏中设计的模式/动作会对每一行执行一次
。就是:
total2164
drwxr-xr-x3
-rw-r--r--1
-rw-r--r--1
-rw-r--r-1
…………………
如果你要精确地控制输出,也可以使用printf命令,这个命令的格式是:
printfformat,item1,item2,...
format参数就是C语言里面的格式控制符,例如%c,%d,%f等等。在%与格式控制
字母之间可加入modifier,modifier是用来进一步控制输出的格式。可能的modifie
r如下所示:
'-'使用在width之前,指明是向左靠齐。如果'-'没有出现,则会在被指定的
宽度向右靠齐。例如:
printf"%-4S","foo"会印出'foo'。
'width'这一个数字指示相对应的栏位印出时的宽度。例如:
printf"%4s","foo"会印出'foo'。
width的值是一个最小宽度而非最大宽度。如果一个item的值需要的宽度
比width大,则不受width的影响。例如printf"%4s","foobar"将印出'foobar'。
'.prec'此数字指定印出时的精确度。它指定小数点右边的位数。如果是要印出一个
字串,它指定此字串最多会被印出多少个字符。
作为一种脚本语言,gawk允许使用变量,定义变量非常简单,就是直接用等号对它赋
值。为了在gawk程序的开始处对变量赋值,gawk专门提供了BEGIN语句,这个语句将在所
有行被读入之前执行,而且只执行一次,通常用它来执行初始化命令,例如
BEGIN{sum=0;count=0;average=0.0;}
对于变量可以使用数学表达式进行运算,运算符包括常见的加减乘除算符,以及^(乘
方),%(取余)和著名的++,--。不过注意gawk在做除法的时候总是使用浮点除法,除了
取余算符%。
函数
另外,gawk包含下列函数:
数学函数
atan2(x,y)y/x的正切
cos(x)余弦函数
sin(x)正弦函数
int(x)取整
log(x)取自然对数
exp(x)指数函数
rand(x)生成一个0到1之间的随机数
srand()初始化随机数发生器
systime()返回从1970年1月1日0:00到当前时间的秒数
sqrt(x)取x的平方根
字符串函数
index(string1,string2)
它会在string1里面,寻找string2第一次出现的地方,返回值是字串string2出
现在字串string1里面的位置。如果找不到,返回值为0。
例如:
printindex("peanut","an")
会印出3。
length(string)
string字符串的长度
例如:
length("abcde")
是5。
match(string,regexp)
match函数会在字串string里面,寻找符合regexp的最长、最靠左边的子字
串。返回值是regexp在string的开始位置,即index值。这个函数会设定内部变量
RSTART等於index,内部变量RLENGTH等於符合的子串个数。如果不符合,则会设定
RSTART为0、RLENGTH为-1。
sprintf(format,expression1,...)
跟C语言的sprintf差不多。
例如:
sprintf("pi=%.2f(approx.)',22/7)
传回的字串为"pi=3.14(approx.)"
sub(regexp,replacement,target)
在字串target里面,寻找符合regexp的最长、最靠左边的地方,并且以字串
replacement代替最左边的regexp。
例如:
str="water,water,everywhere"
sub(/at/,"ith",str)
结果字串str会变成
"wither,water,everywhere"
gsub(regexp,replacement,target)
gsub与前面的sub类似。在字串target里面,寻找符合regexp的所有地方
,以字串replacement代替所有的regexp。
例如:
str="water,water,everywhere"
gsub(/at/,"ith",str)
结果字串str会变成
'wither,wither,everywhere"
substr(string,start,length)
传回字串string的子字串,这个子字串的长度为length个字符,从第start
个位置开始。
例如:
substr("washington",5,3)
传回值为"ing"
如果length没有出现,则传回的子字串是从第start个位置开始至结束。
例如:
substr("washington",5)
传回值为"ington"
tolower(string)
将字串string的大写字母改为小写字母。
例如:
tolower("MiXeDcAsE123")
传回值为"mixedcase123"
toupper(string)
将字串string的小写字母改为大写字母。
例如:
toupper("MiXeDcAsE123")
传回值为"MIXEDCASE123"
其他函数
system(command)
此函式允许使用者执行作业系统的指令,执行完毕後将回到gawk
程式。
例如:
BEGIN{system("ls")}
控制流
在gawk命令脚本中可以使用控制流,主要是if,for,while等语句,用法和C语言相当
类似:
if(condition)then-body[elseelse-body]
如果condition为真(true),则执行then-body,否则执行else-body。
举一个例子如下:
if(x%2==0)
print"xiseven"
else
print"xisodd"
while(condition)
body
while语句测试condition表达式。假如condition为真则执行body的语句。一次
执行完後,会再测试condition,假如condition为真,则body会再度被执行。这个
过程会一直被重复直到condition不再是真。如果condition第一次测试就是伪(fals
e),则body从没有被执行。
下面的例子会印出每个输入行的前三个栏位。
gawk'{i=1
while(i<=3){
print$i
i++
}
}'
do
body
while(condition)
这个doloop执行body一次,然後只要condition是真则会重复执行body。即使
开始时condition是伪,body也会被执行一次。
下面的例子会印出每个输入记录十次。
gawk'{i=1
do{
print$0
i++
}while(i<=10)
}'
for(initialization;condition;increment)
body
此叙述开始时会执行initialization,然後只要condition是真,它
会重复执行body与做increment。
下面的例子会印出每个输入记录的前三个栏位。
gawk'{for(i=1;i<=3;i++)
print$i
}'
break会跳出包含它的for、while、do-while循环的最内层。
下面的例子会找出任何整数的最小除数,它也会判断是否为质数。
gawk'#findsmallestdivisorofnum
{num=$1
for(div=2;div*div<=num;div++)
if(num%div==0)
break
if(num%div==0)
printf"Smallestdivisorof%dis%d/n",num,div
else
printf"%disprime/n",num}'
continue使用于for、while、do-while循环内部,它会跳过循环体的剩余部分
,立刻进行下一次循环的执行。
下面的例子会印出0至20的全部数字,但是5并不会被印出。
gawk'BEGIN{
for(x=0;x<=20;x++){
if(x==5)
continue
printf("%d",x)
}
print""
}'
next语句强迫gawk立刻停止处理目前的行而继续下一个输入行。
exit语句会使得gawk程式停止执行而跳出。然而,如果END出现,它会去执
行END的actions。
自定义函数
你可以定义自己的函数,其格式是
functionname(parameter-list){
body-of-function
}
name是所定义的函数名字。parameter-list是函数的变量列表。变量间使用逗号分
开。
函数可以在程序的任何地方定义,不过习惯上总是定义在程序的开头部分。
下面这个例子,会将每个记录的第一个栏位之值的平方与第二个栏位之值的平方加
起来。
{print"sum=",SquareSum($1,$2)}
functionSquareSum(x,y){
sum=x*x+y*y
returnsum
}
如果你熟悉任何编程语言,那么掌握awk都是很轻松的事情,如果你不喜欢它,那么你
可以参考我们下面介绍的perl。
11.3Perl
Perl是从awk发展起来的,它由LarryWall在1986年发明。它是一种功能强大的编程语
言,而且可以在许多平台上使用。实际上,你完全可以将Perl作为一种标准编程语言(
而不是脚本语言)来使用,笔者非常喜欢它,并且建议所有不想学习C语言的UNIX管理员
应该掌握Perl的基本编程技术。目前,常用的版本是perl5,几乎所有的Linux发行版本
都会包含它,缺省时,linux的perl5安装在/usr/bin下,命令是/usr/bin/perl.
11.3.1基本语法
perl的语法介于C和basic之间,一个perl程序由若干行组成,使用的时候由perl解释
程序解释执行。每个完整的行都应该用分号结尾。
Perl的基本语法是这样的:
①变量和运算符
在perl中,所有变量都不需要提前声明。一旦对某个变量赋值,就自动产生了这个变
量。perl的变量有普通变量,数组和关联数组三种。普通变量就是数值和字符串,要声
明一个普通变量,在变量名字前面加上$,例如
$string1="aaa";
$test=5;
$u=1.33;
同样,访问变量内容也需要使用$符号。
数组用@字符标志,如
@name1=("tom","marry","john");
$b=$name[0];$b现在等于"tom"
$b=@name[0];跟上一句是一样的
$name[0,2]=["help","so"];现在@name等于[“help","marry","so"]
@name[0,2]==@name[2,0];交换0,2元素
数组的大小不是固定的,你可以动态地添加数组元素,例如
$name[3]="app";增加一个元素
直接访问数组名字将得到数组中元素的个数,例如:
$count=@name;将name的元素个数存放到$count变量中。
关联数组是一种特殊的数组,每个元素都由一对元素构成。或者说,关联数组是一种
下标不是整数的数组,要声明一个关联数组,使用%符号,例如:
%arr=(1,"one",2,"two",3,"three",4,"four");
这时可以用前面的值(key)来索引后面的值:
$one=$arr{1};这时$one等于"one"
注意关联数组的访问方式,是使用$关联数组名字[索引号]。
你可以把关联数组看成数据库的一种实现。与一般的数组一样,其大小也可以动态调
节:
$arr{5}="five";增加一对数据。
可以将关联数组简单地变成普通数组,例如
@X=%arr;现在@X的内容是X[0]="1",X[1]="one",……………
perl的运算符与C语言以及我们介绍的gawk很相似,包括普通的+-*/%以及来自C语言的
逻辑运算符&&(和),||(或),等等,下面是一个列表:
+-*/四则运算,注意perl的除法是浮点除法
$a%$ba对b取余数,例如3%2的结果是1
$1..$2区段运算符,这个算符取出$1和$2中间的所有值,例如1..9返回一个表
1,2,………9。通常用这个命令初始化一个数组,例如:@dec=1..9;@oth=(1..26,'A
'..'Z')等等。
=赋值算符
><>=<===!=
这几个算符是数字之间的比较算符。
perl中没有专门的boolean型变量,而是象C语言一样认为所有不为零的量为真值,而
0或者空字符串为假。与C语言类似,Perl支持以下的逻辑运算符:
&&与||或!非
同样,perl也支持位运算:
&与||或^异或
还有就是与C语言相似的运算符使用方式,如
$i+=$j;等效于$i=$i+$j,同样还可以使用$i-=5;$i&=12。这样的算式
$i++;等效于C语言的++,将i加一,++$i,$i--,--$i都是可以使用的。
除了上面的标准算式之外,perl支持字符串运算,首先是字符串之间的比较命令:
$str1gt$str2$str1大于$str2
$str1lt$str2$str1小于$str2
$str1ge$str2$str1不小于$str2
$str1le$str2$str1不大于$str2
$str1eq$str2$str1等于$str2
$str1ne$str2$str1不等于$str2
$str1cmp$str2根据$str1是大于,等于还是小于$str2,返回1,0或者-1。
上面的字符串比较都是使用字典顺序,即ASCII码的顺序。
另一个非常有用的运算符是点号运算符,这个运算符用于把两个字符串连接成一个,
例如:
$str1="string1";
$str2="string2";
$string3=$str1.$str2;这时$string3等于"string1string2"
②基本语句和函数:
#
这个符号代表注释的开始。
显示字符串,写文件,如
print"hello/n";或者print"thevaris$i","/n";注意变量名会自动地被替换成变
量值,除非你用一个/符号明确地告诉perl:
print"/$iisastr";
printFILE"hello/n";向FILE对应的文件写,FILE是一个文件句柄;
split分割字符串,格式split(/模式/,$string);
例如$string="i:am:perl";
@list=split(/:/,$string);
#这时@list=("i","am","perl")
($a,$b,$c)=split(/:/,$string);
delete$ARRAY(key)
这个函数用于在关联数组中删除一对记录。例如,%arr=(1,”one”,2,”two”,3,”
three”);delete$arr(2);执行上述操作之后,%arr的内容变为(1,”one”,2,”two
”)。
keys(%ARRAY)
取出关联数组%ARRAY中所有的索引key。这个操作将返回一个数组。例如,对于上面的
%arr,执行@test=key(%arr)的结果是@test成为(1,2)。
values(%ARRAY)
取出关联数组%ARRAY中所有的value,同样返回一个数组,例如对于%arr,@test=val
ues(%arr)的结果是@test变成(”one”,”two”)。
reverse(@array)
把@array反转排列。例如@test=(1,2,5,3,10),@other=reverse(@test)的结果是@ot
her变成(10,3,5,2,1)。
sort(@array)
排序,注意这个排序是按照字符串的排序,例如@other=sort(@other)的结果是(1,
10,2,3,5)。
chop($string)
删除字符串的最后一个字符,通常用于去掉输入字符串中的回车符。
lenth($string)
取字符串长度
substr($string,offset,length)
取字符串子串,即从$string的offset偏移量处截取length长度的字符串作为子串返回
index($string,$substring)
在$string中查找$substring,成功的话,返回$substring在$string中的偏移量,如
果不存在就返回-1。
push(@array,$string)
在@array末尾加入$string
pop(@array)
删除@array的末尾元素并返回这个元素
shift(@array)
删除@array的开头元素并且返回这个元素
join($string,@array)
在@array中间加入$string并返回结果
grep(/pattern/,@array)
在@array中用正则方式查找符合条件的元素
hex($string)
将16进制转化为十进制
rand
产生随机数,注意应该先执行srand初始化随机数种子。
localtime
返回时间数组
dieLIST
显示字符串并且退出程序
pack("格式”,LIST)
把一个LIST转换成指定的二进制格式,例如:$string=pack('C",65)这时$string等于
ASCII的65,即"A"
反引号
用反引号将某个字符串括起来的效果是使perl执行系统命令,这里使用的反引号是大
键盘最左边键,如`ls`执行ls命令。
③使用文件
在perl中使用文本文件非常简单,只要使用open和close打开和关闭文件:
open打开文件
close关闭文件
open函数的格式是open(Filehandle,$filename),这个操作将会打开$filename文件
,并且让Filehandle句柄指向打开的文件。如果失败,将返回false。缺省下,文件是以
只读的方式打开的。如果要打开名字为$filename文件用于输出,使用open(Filehandle
,">$filename")。想要在某个文件的后面追加内容,使用open(Filehandle,">>$filena
me")。当然,open(Filehandle,"<$filename")也是可以使用的,不过这就等于open(Fi
lehandle,"$filename")。
read读文件,格式是read(Filehandle,$string,length),这函数从Filehandle指向
的文件中读取length个字符,存放到$string变量中。如果你要得到标准输入,使用STD
IN的句柄。
close(Filehandle)将关闭由open语句打开的文件。
除了用read语句的标准方法之外,还有一个经常用的方法:
$filecontent=<FILE>;从句柄FILE指向的文件中读取一行,内容存入$filecontent变
量。如果你要从控制台读取一个字符串,使用$input=<STDIN>;就可以了。
下面是一个例子:
$filename="test";
open(FILE,"$filename")||die"cannotopenfile!;
while($line=<FILE>{
print"$line";
}
close(FILE);
这个程序实际就是cat命令的perl语言实现,open命令打开当前目录下面的test文件,
并且把句柄返回到FILE变量,注意这一行的用法,Perl的||(或)运算是短路求值的,如
果open成功,那么返回一个非0的数,因此这算式无论如何都会为真,所以会跳过||后面
的东西;否则,如果open失败,perl就要对后面的东西执行一下,于是退出这个程序。
打开成功之后,perl会得到这个文件的句柄,下面的句子就是反复读取文件的每一行
并且显示出来,当文件读到末尾的时候,$line=<FILE>将产生一个空字符串,于是whil
e循环结束。
与shell脚本语言类似,perl还有一些文件测试运算符
-t$file
如果$file这个文件可读,返回1,$file是文件名。
-w$file
如果$file可写,返回1
-x$file
如果$file可以执行,返回1
-e$file
如果$file存在,返回1
-o$file
如果用户是$file的拥有者,返回1
-s$file
返回$file文件的大小
-f$file
是否为正常文件
-T$file
是否文本
-B$file
是否二进制文件
-M$file
文件从更新到现在的日期数
④流程控制
perl支持与C语言很相似的流程控制语句:
if和if..else:
if语句的语法是
if(...){
clause;
}
与C语言不同,即使只有一行程序,if后面的花括号也不能省略,这一点也适用于后面
说的其他复合语句。
与C语言类似,也可以用else和elseif子句:
if(...){
clause1;}
else{
clause2;
}
或者
if(…){
...
}
elseif(…){
....
}
else{
...
}
另外,perl还支持unless语句:
unless(exp1){
clause1;
}
如果exp1不成立,就执行clause1子句。这个unless语句里面也可以使用else子句。实
际上,这就是一种否定形式的if……else语句。
while循环语句:
while的语法有两种,分别是将表达式放在循环首部和尾部,第一种形式是:
while(exp){
clause;
}
第二种形式是
do{
clause;
}
while(exp);
都是循环执行clause直到exp不成立,不过一个在循环头部判断exp表达式是否为真,
另一个是在循环尾部。
until循环
语法是until(exp){
clause;
}
反复执行clause直到exp成立。
for循环
for(初始化;继续条件;增量){
循环体;
}
这个for循环和C的一样,首先执行初始化语句,然后开始循环执行循环体,每次循环
都调用一次增量表达式,直到循环继续条件不再成立。例如
for($1=0;$i<10;$i++){
print$i;
}
将显示出从0到9的所有整数。
foreach$variable(@array){
循环体;
}
这个类似于shell语言的foreach,它把@array的内容一条一条赋给$variable并执行里
面的语句。
跳出循环
有两个语句用来实现特殊控制:
lastif用在循环里,相当于break;
nextif相当于continue.
⑤文字处理运算
除了正常的字符串处理语句外,perl还支持一种文字处理运算方式,基本格式是$str
ing=~(文字处理模式)。这个文字处理模式是perl的主要优点之一,由于perl的文字处
理运算模式太强大了,这里只能介绍几个非常基本的形式。
首先解释一下pattern的概念.pattern一般是用两个/字符夹在一起的一些字符串,用
来代表一些具有某些特点的字符串,实际上,这个patternj基本上就是grep/egrep里面
的正则表达式,只是功能更丰富一点。常用的有:
任意字符串:匹配该字符串
[0-9]匹配所有数字字符
[a-z]所有小写字母
[^0-9]所有的非数字
[^a-z]所有的非小写字母
[A-Z]所有的大写字母
^字符串开头的字符
$字符串结尾的字符
/d跟[0-9]一样
/D非数字字符
/w就相当于[a-zA-Z0-9]
/W相当于[^a-zA-Z0-9]
/s一个空白的字符
/S非空白的字符
/d+一个相当于数字的字符串
/w+一个完全由数字或字符构成的字符串
/b一个不由英文字母或者数字为边界的字符串
/B一个由字母或数字为边界的字符串
a|b|c符合a,b,c之一的字符串
/pattern/ii代表忽略大小写
[]找寻符合[]内的字符,例如[abde]可以匹配a,b,d,e的任何一种
?{m}正好是m个指定的字母
{m,n}多于m少于n个指定的字符
/如果要引用一些在pattern中具有特殊意义的字符,使用/前缀
在perl的文本运算模式中,最常用的是=~或者!~运算符号和s,tr两个函数。=~表示匹配
,它用右边的模式来匹配左边的字符串,如果成功就得到一个true,!~正好相反,代表
不匹配,例如
$string="chmod711cgi";
if($string=~"/chmod/"){
print"Foundchmod!/n";}
$string=~"/chmod/"这样的表达式询问是否/chmod/可以匹配$string,因为$string中
包含chmod,所以if语句会成功地执行。
tr是串转换函数,例如:
$string=~tr/a-z/A-Z/;
将字符串中的小写字母转换成大写.
s是串取代函数,例如:
$string=~s/a/A/;
把第一个a换成A,还可以加后缀g表示全程替换,例如:
$string=~s/1/A/g;
变换后,$string变成chmod7AAcgi.
注意tr和s的区别,tr的多替换一般是一对一的,或者说是字符的替换,而s是字符串的
替换,长度可以改变,例如如果$string的值是chmod711cgi,那么
$string=~s/1/ONE/g;
将变成chmod7ONEONEcgi.而
$string=~tr/1/ONE/;
将把$string变成chmod7oocgi。
还有一个很实用的功能是变数替换,例如:
$string="test24";
$string=~s/(/d+)/<$1>/;
这时,s首先搜索满足/d+(数字)的串,得到24,然后送入$1,接着再套上<>,结果是"tes
t<24>".
⑥内置变量
除了用户定义的变量之外,perl还定义了一些内置变量,它们在perl中有特殊的意义
,用户不能修改它们的含义(有些可以赋值),下面是常用的内置变量:
@ARGV
这是个数组,它代表的是传递给perl程序的命令行开关,如@ARGV[0]是第一个参数,
@ARGV[1]是第二个等等。如果你的perl程序名字叫test,而你用testmeother去调用它
,那么@ARGV[0]是”me”,@ARGV[1]是other,以此类推。
$_和$1,$2,………
这几个参数用于文本处理模式中的临时变量。举个例子来说,串匹配模式中:
$string="chmod711cgi"
$string=~/(/w+)/s+(/d+)/;
看上去这第二行代码什么也不做,因为它仅仅是个匹配语句。不过,实际上,由于pe
rl会把临时变量放进$n变量,所以它会修改$_和$1,………变量。在这个匹配模式中,
首先的/w+匹配一组字符,成功,得到chmod字符串,于是perl将它保存到$1;然后,/s
+匹配一组空白符号,失败;最后,/d+匹配一组数字,成功,得到711,perl将它保存到
$2。
如果在匹配模式中没有指明对那个串变量使用匹配模式,就使用$_进行匹配。
⑦自定义函数
Perl程序中允许定义自己的子程序。例如,下面的语句定义了一个子过程:
submy_proc{
print“thisismysubrouting/n”;
}
sub是子过程的说明,my_proc是过程名字,要调用这个过程,只要使用&符号,例如:
if($want==1){
&my_proc;
}
11.3.2perl的使用
上面介绍了perl的基本语法。要使用perl,你当然可以在交互模式下使用,但是,一
般情况下,我们用perl是代替shell脚本完成自动化任务的。为此,我们需要把perl写成
程序来运行。写perl程序可以用任何文本编辑工具创建,一般总是设置其扩展名为.pl,
虽然实际上扩展名是不需要的。
要运行一个perl程序,有两种方法,一种是调用perl解释器读入perl源程序,例如,
我们已经写了一个perl程序,命名为test.pl,那么,可以用下面的命令执行它:
$/usr/bin/perltest.pl
不过,在一般情况下,我们更喜欢在命令行下面直接敲入程序的名字执行它,为此,
可以在perl程序的头部加入这样的行:
#!/usr/bin/perl
注意#!符号,它告诉shell应该用什么程序来解释当前脚本,这里的定义是/usr/bin/
perl,这是缺省的的perl安装位置。如果你的perl可执行程序放在别的目录下,自己修
改这一行。这样,当shell读到这个文件的时候,就会自动启动perl来解释这个程序。
perl最常用的功能是用来写cgi程序,不过,我们不想涉及cgi程序的细节。相反,我
们介绍如何用perl进行日常管理,用perl程序代替书写晦涩的shell脚本。
让我们从一个我自己的例子开始,我经常要把一些txt文本直接转化成html文本,以便
做进一步的编辑和主页发布,其实这个操作非常简单,就是将回车和大于号,小于号都
换成对应的HTML标记,这可以用word或者netscape来完成,但是如果涉及的文件数目比
较多或者文件比较大,用这些软件就很困难了,所以我写了一个十分简单的perl脚本:
#!/usr/bin/perl
if((@ARGV[0]eq"")||(@ARGV[1]eq"")){
print"convertinputfileoutputfile/n";
exit;}
open(FILE1,"@ARGV[0]")||die"cannotopensourcefile!/n";
open(FILE2,">@ARGV[1]")||die"cannotopentagetfile!/n";
while($line=<FILE1>){
$line=~s/</</g;
$line=~s/>/>/g;
$line=~s//^M//g;
$line=~s//n/<BR>/g;
printFILE2$line;
}
close(FILE1);
close(FILE2);
这个程序简单得几乎象是DOS的批命令,首先检查参数是否定义,然后从输入文件中读
取行,把回车和两个尖括号换成对应的html标记,写入对应文件,任务就完成了。要使
用它,比如把test.txt转换成test.html,可以直接执行:
./convert.pltest.txttest.html
perl也可以完成更复杂的操作,最常见的功能扩展是进行网络编程,如直接使用电子
邮件,电子新闻服务等等。不过我们这里不能进一步介绍它的强大功能。对perl感兴趣
的朋友,可以进一步查阅有关书籍学习编程技术。
11.4其他工具
还有很多自动化脚本工具,例如python等等。另外,对于一个职业的系统管理人员,
熟悉C语言的编程是很有好处的。
就我个人而言,我感到,如果你不想学习shell,那么了解expect和perl就足以对付一
般的系统管理工作。另外,还有一些威力强大的可编程工具,一个是我们刚才提到的py
thon,这是一种面向对象的脚本平台,如果你的大部分任务使用shell和expect,那么这
个东西可能很适合你使用。
另外一个非常有争议的产品是emacs。这个编辑工具是GNU计划的头号产物,随着发展
,它已经从原来一个文本编辑程序发展成为一个使用lisp宏控制,几乎可以做文本界面
下的一切事情的集成环境。反对它的理由主要是它的运行速度在低配置的机器上几乎无
法忍受,而且配置起来也十分困难。不论如何,使用emacs有时显得比较有专业特色,至
少是很有GNU的特色
相关推荐
你可以使用UNIX/LINUX中一些比较简单的命令或命令组合来执行1、2、3、4、5的任务。对于任务6和7,你需要编写单独的Shell脚本文件(必须分别命名为add和delete)并且在你的主脚本menu文件中调用这些脚本文件。
你可以使用UNIX/LINUX中一些比较简单的命令或命令组合来执行1、2、3、4、5的任务。对于任务6和7,你需要编写单独的Shell脚本文件(必须分别命名为add和delete)并且在你的主脚本menu文件中调用这些脚本文件。 ...
WinSCP (Windows Secure Copy) 是一个免费、开源的Windows应用程序,主要用于通过...脚本和自动化:WinSCP支持脚本和自动化功能,允许用户自动执行文件传输和同步任务。这对于需要定期执行文件备份或更新的任务非常有
它能把远端 Unix/Linux 的桌面无缝地带到你的Windows上,甚至当你的电脑是在内网或防火墙后,你也能通过 SSH 协议安全的运行远端的X应用程序。 NetSarang Xmanager Enterprise 特点包括: -可通过 Xcongfig 工具...
脚本支持 - 支持用户通过脚本自动化日常任务,提高工作效率。 图形用户界面 - 提供直观的图形界面,使得用户可以轻松配置和管理各种选项。 安全性 - 提供高级的加密和认证选项,确保远程连接的安全性。 兼容性 - ...
资源包含sshxcute-1.0.jar及中文使用指南; sshxcute框架简介: 软件开发与测试人员常常会在远程 Linux/UNIX 系统上执行...sshxcute 不管是针对软件开发、测试还是系统部署,都简化了自动化流程与系统环境部署的步骤。
9、crond:cron是Unix下的一个传统程序,该程序周期地运行用户调度的任务。比起传统的Unix版本,Vixie版本添加了不少属性,而且更安全,配置更简单。 10、dhcpd:该精灵提供了对动态主机控制协议(Dynamic Host ...
Puppet - Linux、Unix和Windows系统的自动化管理引擎,执行管理任务(例如添加用户,安装包和更新服务器配置)基于一个集中的规范。
puppet是一种Linux、Unix、windows平台的集中配置管理系统,使用自有的puppet描述语言,可管理配置文件、用户、cron任务、软件包、系统服务等。puppet把这些系统实体称之为资源,puppet的设计目标是简化对这些资源的...
9.22 运行时的环境—从 UNIX/Linux 中使用 Postgres 270 9.22.1 启动 postmaster 270 9.22.2 使用 pg_options 270 9.22.3 认可的选项 271 9.23 安全 273 9.23.1 用户验证 273 9.23.2 基于主机的访问控制 273 9.23.3...
主要内容包括如何使小到中型的系统管理任务自动化,分析系统数据并编辑配置文件,使用bash和ksh等编写Linux、Unix和OS X应用程序的脚本文件等。 本书面向中高级的shell程序员,以及需要解决日常问题的系统管理员,但...
• 第五部分—编写Shell 脚本介绍了shell 编程,一个无可否认的基本技能,能够自动化许 多常见的计算任务,很容易学。通过学习shell 编程,你会逐渐熟悉一些关于编程语言方 面的概念,这些概念也适用于其他的编程...
第1章 Red Hat Linux和UNIX简介 1 1.1 Linux的优点 2 1.2 版权和保证 3 1.3 在哪里可以获取Red Hat Linux 3 1.4 系统需求 3 1.5 小结 4 第2章 Red Hat系统的安装 5 2.1 准备,认真准备 5 2.2 安装Red Hat Linux 6 ...
1、跨系统、跨平台支持,Windows/Linux/Unix一机(软件)拿下; 2、混合实例技术,不论本地/远程,一机(软件)即可管理所支持的所有数据库软件; 3、自动(计划任务模式)/手工备份本地或远程MSSQL、ORACLE、...
快速关闭Linux系统 最新版本的Linux/UNIX系统借鉴了大型机的技术,采用了抗掉电的日志式文件系统,可以自动跟踪保存用户数据,自动同步刷新文件系统,用户完全可以随手关闭电源,从而达到快速关闭系统的目的。...
不过目前大多数较新的Linux发行版本(包括红旗 Linux、中软Linux、Mandrake Linux等)都可以自动挂装文件系统,但Red Hat Linux除外。 umount 1.作用 umount命令的作用是卸载一个文件系统,它的使用权限是超级...
对于面向所有主流Linux子系统的支持与管理任务,本书都进行了恰到好处的讲解。涵盖的主题包括文件系统、目录、引导和关机、打印、网络兼容性、网络应用、网络登录、安全、用户账号、数据备份等等。此外,还针对TCP/...
1、跨系统、跨平台支持,Windows/Linux/Unix一机(软件)拿下; 2、创新的集中式管理技术,只需在一台计算机安装,即可管理无限台计算机的数据库/文件备份; 3、混合实例技术,可无限扩展任意实例与任务,不在需要...