|
楼主 |
发表于 2006-3-14 20:17:21
|
显示全部楼层
#搜索备份,正在看rc.firewall,搜索到的相关文章
gawk的使用方法
本文出自: 作者: (2002-03-02 14:01:59)
第一章 前言
第二章 简介
第三章 读取输入档案
第四章 印出
第五章 Patterns
第六章 算式(Expression)作为Actions的叙述
第七章 Actions里面的控制叙述
第八章 内建函式(Built-in Functions)
第九章 使用者定义的函式
第十章 □例
第十一章 结论
=======================================
第一章前言
awk是一个程式语言,对於资料的处理具有很强的功能。对於文字档里的资料做
修改、比对、抽取等的处理,awk能够以很短的程式轻易地完成。如果使用C
或Pascal等语言写程式完成上述的动作,会不方便且很花费时间,所写的程
式也会很大。
awk能够依照使用者的定义格式来分解输入资料,也可依照使用者定义的格式
来印出资料。awk名称的由来是由它的原始设计者的姓氏之第一个字母而命
名:AlfredV.Aho,PeterJ.Weinberger,BrianW.Kernighan。
awk最初在1977年完成。一个新版本的awk在1985年被发表,它的功能比旧版本
增强不少。gawk是GNU所做的awk,gawk最初在1986年完成,之後不断地被
改进、更新。gawk包含awk的所有功能。往後的gawk将以下面的2个输入档
案来做例子说明。
档案'BBS-list':
aardvark555-55531200/300B
alpo-net555-34122400/1200/300A
barfly555-76851200/300A
bites555-16752400/1200/300A
camelot555-0542300C
core555-29121200/300C
fooey555-12342400/1200/300B
foot555-66991200/300B
macfoo555-64801200/300A
sdace555-34302400/1200/300A
sabafoo555-21271200/300C
档案'shipped':
Jan132515115
Feb153224226
Mar152434228
Apr315263420
May163429208J
un314275492
Jul243467436
Aug153447316
Sep135537277
Oct295468525
Nov208782577
Dec173561401
Jan213664620
Feb265880652
Mar247570495
Apr217074514
第二章简介
gawk的主要功能是针对档案的每一行(line)搜寻指定的patterns
。当一行里有符合指定的patterns,gawk就会在此一行执行被指定
的actions。gawk依此方式处理输入档案的每一行直到输入档案结
束。
gawk程式是由很多的pattern与action所组成,action写在
大括号{}里面,一个pattern後面就跟著一个action。整个gawk程
式会像下面的样子:
pattern{action}
pattern{action}
在gawk程式里面的规则,pattern或action能够被省略,但
是两个不能同时被省略。如果pattern被省略,对於输入档里面的
每一行,action都会被执行。如果action被省略,内定的action
则会印出所有符合pattern的输入行。
2.1如何执行gawk程式
基本上,有2个方法可以执行gawk程式。
□如果gawk程式很短,则gawk可以直接写在commandline,如下所示:
gawk 'program' input-file1 input-file2...
其中program包括一些pattern和action。
□如果gawk程式较长,较为方便的做法是将gawk程式存在一个档案,
即patterns与actions写在档名为program-file的档案里面,执行
gawk的格式如下所示:
gawk -f program-file input-file1 input-file2...
gawk程式的档案不止一个时,执行gawk的格式如下所示:
gawk -f program-file1 -f program-file2...input-file1
input-file2...
2.2一个简单的例子
现在我们举一个简单的例子,因为gawk程式很短,所以将gawk程
式直接写在commandline。
gawk '/foo/{print$0}' BBS-list
实际的gawk程式为/foo/{print$0}。/foo/为pattern,意思为搜
寻输入档里的每一行是否含有子字串'foo',如果含有'foo'则执行action。
action为print$0,是将现在这一行的内容印出。BBS-list是输入的档案。
执行完上述指令後,会印出下面的结果:
fooey555-12342400/1200/300B
foot555-66991200/300B
macfoo555-64801200/300A
sabafoo555-21271200/300C
2.3一个较复杂的例子
gawk'$1=="Feb"{sum=$2+$3}END{printsum}'shipped
现在这个例子会将输入档'shipped'的第一个栏位与"Feb"做比较
,如果相等,则其对应的第2栏位与第3栏位的值会被加到变数sum。
对於输入档的每一行重复上述的动作,直到输入档的每一行都被处理
过为止。最後将sum的值印出。END{printsum}的意思为在所有的输
入读完之後,执行一次printsum的动作,也就是把sum的值印出。
下面是执行的结果:
84
第三章读取输入档案
gawk的输入可以从标准输入或指定的档案里读取。输入的读取单
位被称为”记录”(records),gawk在做处理时,是一个记录一个记(p9of46)
录地处理。每个记录的内定值是一行(line),一个记录又被分为多个
栏位(fields)。
3.1如何将输入分解成记录(records)
gawk语言会把输入分解成记录(record)。记录与记录之间是以
recordseparator隔开,recordseparator的内定值是表示新一行的
字元(newlinecharacter),因此内定的recordseparator使得文字
的每一行是一个记录。
recordseparator随著内建变数RS的改变而改变。RS是一个字串,
它的内定值是""。仅有RS的第一个字元是有效的,它被当作record
separator,而RS的其它字元会被忽略。
内建变数FNR会储存目前的输入档案已颈欢寥〉募锹贾?鍪?D
建变数NR会储存目前为止所有的输入档案已颈欢寥〉募锹贾?鍪?
3.2栏位(field)
gawk会自动将每个记录分解成多个栏位(field)。类似於字在一
行里面,gawk的内定动作会认为栏位之间是以whitespace分开。在
gawk里,whitespace的意思是一个或多个空白或tabs。
在gawk程式里面,以'$1'表示第一个栏位,'$2'表示第二个栏位
,依此类推。举个例子,假设输入的一行如下所示:
Thisseemslikeaprettyniceexample.
第一个栏位或$1是'This',第二个栏位或$2是'seems',依此类推。
有个地方值得特别注意,第七个栏位或$7是'example.'而非'example'。
不论有多少栏位,$NF可用来表示一个记录的最後一个栏位。以
上面的例子为例,$NF与$7相同,也就是'example.'。
NF是一个内建变数,它的值表示目前这个记录之栏位的个数。$0,看起来好像是第零个栏位,它是一个特例,它表示整个记录。
下面是一个较复杂的例子:
gawk'$1~/foo/{print$0}'BBS-list
结果如下:
fooey555-12342400/1200/300B
foot555-66991200/300B
macfoo555-64801200/300A
sabafoo555-21271200/300C
这个例子是把输入档'BBS-list'的每个记录的第一个栏位作检查,如
果它含有子字串'foo',则这一个记录会被印出。
3.3如何将记录分解成栏位
gawk根据fieldseparator将一个记录分解成栏位。fieldsepa-rator以内建变数FS表示。
举个例子,假如fieldseparator是'oo',则下面的行:
moogoogaipan
会被分成三个栏位:'m'、'g'、'gaipan'。
在gawk程式里,可以使用'='来改变FS的值。例如:
gawk'BEGIN{FS=","};{print$2}'
输入行如下:
JohnQ.Smith,29OakSt.,Walamazoo,MI42139
执行gawk的结果将印出字串'29OakSt.'。BEGIN後面的action会在
第一个记录被读取之前执行一次。
第四章印出
在gawk程式里,actions最常做的事就是印出(printing)。简单
的印出,使用printe叙述。复杂格式的印出,使用printf叙述。
4.1print叙述
print叙述用在简单、标准的输出格式。叙述的格式如下所示:
printitem1,item2,...
输出时,各个item之间会以一个空白分开,最後会换行(newline)。
如果'print'叙述之後没有跟著任何东西,它与'print$0'的效
果一样,它会印出现在的记录(record)。要印出空白行可使用'print
""'。印出一段固定的文字,可用双引号将文字的两边括起来,例如
'print"Hellothere"'。
这里是一个例子,它会把每个输入记录的前二个栏位印出:
gawk'{print$1,$2}'shipped
结果如下所示:
Jan13
Feb15
Mar15
Apr31
May16
Jun31
Jul24
Aug15
Sep13
Oct29
Nov20
Dec17
Feb26
Mar24
Apr21
4.2OutputSeparators
前面我们已提过如果print叙述包含有多个item,item之间
用逗点分开,则印出时各个item会被一个空白隔开。你能够使用任何
的字串作为outputfieldseparator,可以居赡诮ū涫?OFS的设
定来更改outputfieldseparator。OFS的初始值为"",即一格的
空白。
整个print叙述的输出被称为outputrecord。print叙述输
出outputrecord之後,会接著输出一个字串,此字串称为output
recordseparator。内建变数ORS用来指明此字串。ORS的初始值
为"",也就是换行。
下面这个例子会印出每个记录的第一个栏位和第二个栏位,此二
(p16of46)
个栏位之间以分号';'分开,每行输出之後会加入一个空白行。
gawk'BEGIN{OFS=";";ORS=""}{print$1,$2}'BBS-list
结果如下所示:
aardvark;555-5553
alpo-net;555-3412
barfly;555-7685
bites;555-1675
camelot;555-0542
core;555-2912
fooey;555-1234
foot;555-6699
macfoo;555-6480
sdace;555-3430
sabafoo;555-2127
4.3printf叙述
printf叙述会使得输出格式较容易精确地控制。printf叙述可以
指定每个item印出的宽度,也可以指定数字的各种型式。
printf叙述的格式如下:
printfformat,item1,item2,...
print与printf的差别是在於format,printf的引数比print
(p18of
多了字串format。format的型式与ANSIC的printf之格式相同。
printf并不会做自动换行的动作。内建变数OFS与ORS对printf叙
述没有任何影响。
格式的指定以字元'%'开始,後面接著格式控制字母。
格式控制字母如下所示:
'c'将数字以ASCII字元印出。
例如'printf"%C",65'会印出字元'A'。
'd'印出十进位的整数。
'i'印出十进位的整数。
'e'将数字以科学符号的形式印出。
例如
print"$4.3e",1950
(p19of
结果会印出'1.950e+03'。
'f'将数字以浮点的形式印出。
'g'将数字以科学符号的形式或浮点的形式印出。数字的绝对值如果
大於等於0.0001则以浮点的形式印出,否则以科学符号的形式印
出。
'o'印出无号的八进位整数。
's'印出一个字串。
'x'印出无号的十六进位整数。10至15以'a'至'f'表示。
'X'印出无号的十六进位整数。10至15以'A'至'F"表示。
'%'它并不是真正的格式控制字母,'%%"将印出"%'。
在%与格式控制字母之间可加入modifier,modifier是用来进一
步控制输出的格式。可能的modifier如下所示:
'-'使用在width之前,指明是向左靠齐。如果'-'没有出现,则会在
被指定的宽度向右靠齐。例如:
printf"%-4S","foo"
会印出'foo'。
'width'这一个数字指示相对应的栏位印出时的宽度。例如:
printf"%4s","foo"
会印出'foo'。
width的值是一个最小宽度而非最大宽度。如果一个item的
值需要的宽度比width大,则不受width的影响。例如
printf"%4s","foobar"
将印出'foobar'。
'.prec'此数字指定印出时的精确度。它指定小数点右边的位数。如
果是要印出一个字串,它指定此字串最多会被印出多少个字
元。
第五章patterns
在gawk程式里面,当pattern符合现在的输入记录(record),其
相对应的action才会被执行。
5.1Pattern的种类
这里对gawk的各种pattern型式作一整理:
/regularexpression/
(p22of
一个regularexpression当作一个pattern。每当输入记录(
record)含有regularexpression就视为符合。
expression
一个单一的expression。当一个值不为0或一个字串不是空的,
则可视为符合。
pat1,pat2
一对的patterns以逗号分开,指定记录的□围。
BEGIN
END
这是特别的pattern,gawk在开始执行或要结束时会分别执行相
对应於BEGIN或END的action。
null
这是一个空的pattern,对於每个输入记录皆视为符合pattern。
(p23of
5.2RegularExpressions当作Patterns
一个regularexpression可简写为regexp,是一种描述字串的方
法。一个regularexpression以斜线('/')包围当作gawk的pattern。
如果输入记录含有regexp就视为符合。例如:pattern为/foo/,
对於任何输入记录含有'foo'则视为符合。
下面的例子会将含有'foo'的输入记录之第2个栏位印出。
gawk'/foo/{print$2}''BBS-list
结果如下:
555-1234
555-6699
555-6480
555-2127
regexp也能使用在比较的算式。
(p24of
exp~/regexp/
如果exp符合regexp,则结果为真(true)。
exp!~/regexp/
如果exp不符合regexp,则结果为真。
5.3比较的算式当作Patterns
比较的pattern用来测试两个数字或字串的关系诸如大於、等於
、小於。下面列出一些比较的pattern:
x
x<=y如果x小於、等於y,则结果为真。
x>y如果x大於y,则结果为真。
x>=y如果x大於、等於y,则结果为真。
x==y如果x等於y,则结果为真。
x!=y如果x不等於y,则结果为真。
x~y如果x符合regularexpressiony,则结果为真。
(p25of
x!~y如果x不符合regularexpressiony,则结果为真。
上面所提到的x与y,如果二者皆是数字则视为数字之间的比较,
否则它们会被转换成字串且以字串的形式做比较。两个字串的比较,
会先比较第一个字元,然後比较第二个字元,依此类推,直到有不同
的地方出现为止。如果两个字串在较短的一个结束之前是相等,则视
为长的字串比短的字串大。例如"10"比"9"小,"abc"比"abcd"小。
5.4使用布林运算的Patterns
一个布林(boolean)pattern是使用布林运算"或"(),"及"
(''&&'),"反"('!')来组合其它的pattern。
例如:
gawk'/2400/&&/foo/'BBS-list
gawk'/2400/||/foo/'BBS-list
gawk'!/foo/'BBS-list
第六章算式(Expression)作为Actions的叙述
算式(Expression)是gawk程式里面action的基本构成者。
6.1算术运算
gawk里的算术运算如下所示:
x+y加
x-y减
-x负
+x正。实际上没有任何影响。
x*y乘
x/y除
x%y求馀数。例如5%3=2。
x^y
x**yx的y次方。例如2^3=8。
6.2比较算式与布林算式
比较算式(comparisonexpression)用来比较字串或数字的关系
,运算符号与C语言相同。表列如下:
x
x<=y
x>y
x>=y
x==y
x!=y
x~y
x!~y
比较的结果为真(true)则其值是1。否则其值是0。
布林算式(booleanexpression)有下面三种:
boolean1&&boolean2
boolean1||boolean2
!boolean
6.3条件算式(ConditionalExpressions)
一个条件式算式是一种特别的算式,它含有3个运算元。
条件式算式与C语言的相同:
selector?if-true-exp:if-false-exp
它有3个子算式。第一个子算式selector首先会被计算。如果是真,
则if-true-exp会被计算且它的值变成整个算式的值。否则if-false-
exp会被计算且它的值变成整个算式的值。
例如下面的例子会产生x的绝对值:
x>0?x:-x
第七章Actions里面的控制叙述
在gawk程式里面,控制叙述诸如if、while等控制程式执行的流
程。在gawk里的控制叙述与C的类似。
很多的控制叙述会包括其它的叙述,被包括的叙述称为body。假
如body里面包括一个以上的叙述,必须以大括弧{}将这些叙述括起
来,而各个叙述之间需以换行(newline)或分号隔开。
7.1if叙述
if(condition)then-body[elseelse-body]
(p30of
如果condition为真(true),则执行then-body,否则执行else-body。
举一个例子如下:
if(x%2==0)
print"xiseven"
else
print"xisodd"
7.2while叙述
while(condition)
body
while叙述做的第一件事就是测试condition。假如condition为真则
执行body的叙述。body的叙述执行完後,会再测试condition,假如
condition为真,则body会再度被执行。这个过程会一直被重复直到
condition不再是真。如果condition第一次测试就是伪(false),则
body从没有被执行。
下面的例子会印出每个输入记录(record)的前三个栏位。
gawk'{i=1
while(i<=3){
print$i
i++
}
}'
7.3do-while叙述
do
body
while(condition)
这个doloop执行body一次,然後只要condition是真则会重复执行body。
(p32of
即使开始时condition是伪,body也会被执行一次。
下面的例子会印出每个输入记录十次。
gawk'{i=1
do{
print$0
i++
}while(i<=10)
}'
7.4for叙述
for(initialization;condition;increment)
body
此叙述开始时会执行initialization,然後只要condition是真,它
会重复执行body与做increment。
下面的例子会印出每个输入记录的前三个栏位。
gawk'{for(i=1;i<=3;i++)
print$i
}'
7.5break叙述
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",num,div
else
printf"%disprime",num}'
7.6continue叙述
(p34of46)
continue叙述使用於for、while、do-while回圈内部,它会跳
过回圈body的剩馀部分,使得它立刻进行下一次回圈的执行。
下面的例子会印出0至20的全部数字,但是5并不会被印出。
gawk'BEGIN{
for(x=0;x<=20;x++){
if(x==5)
continue
printf("%d",x)
}
print""
}'
7.7next叙述、nextfile叙述、exit叙述
next叙述强迫gawk立刻停止处理目前的记录(record)而继续下一
个记录。
nextfile叙述类似next。然而,它强迫gawk立刻停止处理目前
的资料档。
exit叙述会使得gawk程式停止执行而跳出。然而,如果END出现
,它会去执行END的actions。
第八章内建函式(Built-inFunctions)
内建函式是gawk内建的函式,可在gawk程式的任何地方呼叫内建
函式。
8.1数值方面的内建函式
int(x)求出x的整数部份,朝向0的方向做舍去。例如:int(3.9)
是3,int(-3.9)是-3。
(p36of46)
sqrt(x)求出x正的平方根值。例sqrt(4)=2
exp(x)求出x的次方。例exp(2)即是求e*e。
log(x)求出x的自然对数。
sin(x)求出x的sine值,x是弪度量。
cos(x)求出x的cosine值,x是弪度量。
atan2(y,x)求y/x的arctangent值,所求出的值其单位是弪度量。
rand()得出一个乱数值。此乱数值平均分布在0和1之间。这个
值不会是0,也不会是1。
每次执行gawk,rand开始产生数字从相同点或seed。
srand(x)设定产生乱数的开始点或seed为x。如果在第二次你设
定相同的seed值,你将再度得到相同序列的乱数值。
如果省略引数x,例如srand(),则现在的日期、时间会
被当成seed。这个方法可使得乱数值是真正不可预测的。
srand的传回值(returnvalue)是前次所设定的seed值。
8.2字串方面的内建函式
index(in,find)
(p37of46)
它会在字串in里面,寻找字串find第一次出现的地方,传回值是
字串find出现在字串in里面的位置。如果在字串in里面找不到字
串find,则传回值为0。
例如:
printindex("peanut","an")
会印出3。
length(string)
求出string有几个字元。
例如:
length("abcde")
是5。
match(string,regexp)
match函式会在字串string里面,寻找符合regexp的最长、最靠
左边的子字串。传回值是regexp在string的开始位置,即index
值。
match函式会设定内在变数RSTART等於index,它也会设定内在变
数RLENGTH等於符合的字元个数。如果不符合,则会设定RSTART为
0、RLENGTH为-1。
(p38of46)
sprintf(format,expression1,...)
举printf类似,但是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。
例如:
(p39of46)
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"
8.3输入输出的内建函式
close(filename)
将输入或输出的档案filename关闭。
system(command)
此函式允许使用者执行作业系统的指令,执行完毕後将回到gawk
程式。
例如:
BEGIN{system("ls")}
第九章使用者定义的函式(User-definedFunctions)
复杂的gawk程式常常可以使用自己定义的函式来简化。呼叫使用
者定义的函式与呼叫内建函式的方法一样。
9.1函式定义的格式
函式的定义可以放在gawk程式的任何地方。
一个使用者定义的函式其格式如下:
functionname(parameter-list){
body-of-function
}
name是所定义的函式之名称。一个正确的函式名称可包括一序列的字
母、数字、下标线(underscores),但是不可用数字做开头。
parameter-list是列出函式的全部引数(argument),各个引数之
间以逗点隔开。
body-of-function包含gawk的叙述(statement)。它是函式定义
里最重要的部份,它决定函式实际要做何种事。
9.2函式定义的例子
下面这个例子,会将每个记录的第一个栏位之值的平方与第二个
栏位之值的平方加起来。
{print"sum=",SquareSum($1,$2)}
functionSquareSum(x,y){
sum=x*x+y*y
returnsum
}
第十章□例
这里将列出gawk程式的一些例子。
gawk'{if(NF>max)max=NF}
END{printmax}'
此程式会印出所有输入行之中,栏位的最大个数。
gawk'length($0)>80'
此程式会印出一行超过80个字元的每一行。此处只有pattern被
列出,action是采用内定的print。
gawk'NF>0'
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
单的方法,将一个档案里的所有空白行删除。
gawk'{if(NF>0)print}'
对於拥有至少一个栏位的所有行,此程式皆会印出。这是一个简
单的方法,将一个档案里的所有空白行删除。
gawk'BEGIN{for(i=1;i<=7;i++)
printint(101*rand())}'
此程式会印出□围是0到100之间的7个乱数值。
ls-lfiles|gawk'{x+=$4};END{print"totalbytes:"x}'
此程式会印出所有指定的档案之bytes数目的总和。
expandfile|gawk'{if(x
END{print"maximumlinelengthis"x}'
此程式会将指定档案里最长一行的长度印出。expand会将tab改
成space,所以是用实际的右边界来做长度的比较。
gawk'BEGIN{FS=":"}
{print$1|"sort"}'/etc/passwd
此程式会将所有使用者的login名称,依照字母的顺序印出
gawk'{nlines++}
END{printnlines}'
此程式会将一个档案的总行数印出。
gawk'END{printNR}'
此程式也会将一个档案的总行数印出,但是计算行数的工作由gawk
来做。
gawk'{printNR,$0}'
此程式印出档案的内容时,会在每行的最前面印出行号,它的功
能与'cat-n'类似。
第十一章结论
gawk对於资料的处理具有很强的功能。它能够以很短的程式完成
想要做的事,甚至一或二行的程式就能完成指定的工作。同样的一件
工作,以gawk程式来写会比用其它程式语言来写短很多。
gawk是GNU所做的awk,它是公众软体(PublicDomain)可免费使
用。 |
|