脚本语言AWK.docx

上传人:b****6 文档编号:5663610 上传时间:2022-12-30 格式:DOCX 页数:38 大小:35.98KB
下载 相关 举报
脚本语言AWK.docx_第1页
第1页 / 共38页
脚本语言AWK.docx_第2页
第2页 / 共38页
脚本语言AWK.docx_第3页
第3页 / 共38页
脚本语言AWK.docx_第4页
第4页 / 共38页
脚本语言AWK.docx_第5页
第5页 / 共38页
点击查看更多>>
下载资源
资源描述

脚本语言AWK.docx

《脚本语言AWK.docx》由会员分享,可在线阅读,更多相关《脚本语言AWK.docx(38页珍藏版)》请在冰豆网上搜索。

脚本语言AWK.docx

脚本语言AWK

一个员工薪资档(emp.dat):

A125,Jenny,100,210

A341,Dan,110,215

P158,Max,130,209

P148,John,125,220

A123,Linda,95,210

文件中各字段依次为员工ID,姓名,薪资率,及实际工时.ID中的第一码为部门识别码."A","P"分别表示"组装"及"包装"部门。

1.awk程序的主要结构:

awk程序中主要语法是Pattern{Actions}

~(match)!

~(notmatch)

2.Actions是什么:

awk的I/O指令:

print,printf(),getline...

awk的流程控制指令:

if(...){..}else{..},while(...){...}...

3.awk处理{Actions}的语法(缺少Pattern部分):

有时语法Pattern{Actions}中,Pattern部分被省略,只剩{Actions}.这种情形表示"无条件执行这个Actions".

4.awk的字段变量:

字段变量含义

$0一字符串,其内容为目前awk所读入的数据行.

$1$0上第一个字段的数据.

$2$0上第二个字段的数据.

...其余类推

5.读入数据行时,awk更新这些内建的字段变量:

当awk从数据文件中读取一个数据行时,awk会使用内建变量$0予以记录.每当$0被改动时(例如:

读入新的数据行或自行变更$0,...)awk会立刻重新分析$0的字段情况,并将$0上各字段的数据用$1,$2,..予以记录.

6.awk的内建变量:

内建变量含义

NF(NumberofFields)为一整数,其值表$0上所存在的字段数目.

NR(NumberofRecords)为一整数,其值表awk已读入的数据行数目.

RS(RecordSeparator)输出记录的分隔符,默认为换行符

FS字段的分隔符,默认为空格

FILENAMEawk正在处理的数据文件文件名.

ARGC命令行参数个数(不包括awk的选项和awk的程序内容)

ARGV命令行参数序列数组下标从0开始

FNR当前的处理记号(读入了多少域数据?

OFS输出的字段分隔符,默认为空格

例如:

awk从资料文件emp.dat中读入第一笔数据行:

"A125Jenny100210"之后,程序中:

$0之值将是"A125Jenny100210"

$1之值为"A125"

$2之值为"Jenny"

$3之值为100

$4之值为210

$NF之值为4

$NR之值为1

$FILENAME之值为"emp.dat"

7.awk的工作流程:

执行awk时,它会反复进行下列四步骤:

1.自动从指定的数据文件中读取一个数据行.

2.自动更新(Update)相关的内建变量之值.如:

NF,NR,$0...

3.依次执行程序中所有的Pattern{Actions}指令.

4.当执行完程序中所有Pattern{Actions}时,若数据文件中还有未读取的数据,则反复执行步骤1到步骤4.

awk会自动重复进行上述4个步骤,使用者不须于程序中编写这个循环(Loop).

8,打印文件中指定的字段数据并加以计算:

awk处理数据时,它会自动从数据文件中一次读取一笔记录,并会将该数据切分成一个个的字段;程序中可使用$1,$2,...直接取得各个字段的内容.

例:

以文件emp.dat为例,计算每人应发工资并打印报表.

$awk'{print$2,$3*$4}'emp.dat

结果:

Jenny21000

Dan23650

Max27170

John27500

Linda19950

执行awk的语法为:

$awk'awk程序'欲处理的资料文件文件名

本范例中的程序部分为{print$2,$3*$4}.把程序置于命令行时,程序之前后须以'括住.print的参数间彼此以","隔开,印出数据时彼此间会以空白隔开.

将上述的程序部分({print$2,$3*$4})储存于文件pay1.awk中.执行命令时再指定awk程序文件之文件名.这是执行awk的另一种方式,特别适用于程序较大的情况,其语法如下:

$awk-fawk程序文件名数据文件文件名

故执行下列两命令,将产生同样的结果:

$awk-fpay1.awkemp.dat

$awk'{print$2,$3*$4}'emp.dat

读者可使用"-f"参数,让awk主程序使用“其它仅含awk函数的文件中的函数”其语法如下:

$awk-fawk主程序文件名-fawk函数文件名数据文件文件名

awk中也提供与C语言中类似用法的printf()函数.用法一样:

编辑另一个awk程序如下,并取名为pay2.awk:

{printf("%6sWorkhours:

%3dPay:

%5d\n",$2,$3,$3*$4)}

执行下列命令

$awk-fpay2.awkemp.dat

结果:

JennyWorkhours:

100Pay:

21000

DanWorkhours:

110Pay:

23650

MaxWorkhours:

130Pay:

27170

JohnWorkhours:

125Pay:

27500

LindaWorkhours:

 95Pay:

19950

9.选择符合指定条件的记录:

awk中除了>,<,==,!

=,...等关系运算符(RelationalOperators)外,另外提供~(match),!

~(NotMatch)二个关系运算符.利用这两个运算符,可判断某字符串是否包含能匹配所指定正则表达式的子字符串.

例:

组装部门员工调薪5%,(组装部门员工之ID以"A"开头)所有员工最后之薪资率若仍低于100,则以100计:

编写如下之程序,并取名adjust1.awk:

$1~/^A.*/{$3*=1.05}$3<100{$3=100}

{printf("%s%8s%d\n",$1,$2,$3)}

执行下列命令:

$awk-fadjust1.awkemp.dat

结果:

A125   Jenny105

A341     Dan115

P158     Max130

P148    John125

A123   Linda100

说明:

awk的工作程序是:

从数据文件中每次读入一个数据行,依序执行完程序中所有的Pattern{Action}指令:

第一个Pattern{Action}:

$1~/^A.*/{$3*=1.05}

第二个Pattern{Action}:

$3<100{$3=100}

第三个Pattern{Action}:

{printf("%s%8s%d\n",$1,$2,$3)} 

再从数据文件中读进下一笔记录继续进行处理.

建立一个数据文件,并取名为reg.dat此为一学生注册的资料文件;第一栏为学生姓名,气候为该生所修课程。

MaryO.S.Arch.Discrete

SteveD.S.AlgorithmArch.

WangDiscreteGraphicsO.S.

LisaGraphicsA.I.

LilyDiscreteAlgorithm

10.awk中数组的特性:

使用字符串当数组的下标(index).

使用数组前不须宣告数组名及其大小.

例:

希望用数组来记录reg.dat中各门课程的修课人数:

有2个学生修"O.S.",则以Number["O.S."]=2表之.

若修"O.S."的人数增加一人,则Number["O.S."]=Number["O.S."]+1或Number["O.S."]++.

11.取出数组中存储的信息:

awk提供了一个指令,藉由该指令awk会自动找寻数组中使用过的所有下标.使用该指令时,须指定所要找寻的数组,及一个变量.awk会使用该的变量来记录从数组中找到的每一个下标.

例如:

for(courseinNumber){....}

指定用course来记录awk从Number[]中所找到的下标.awk每找到一个下标时,就用course记录该下标之值且执行{....}中之指令.

例:

统计各科修课人数,并印出结果.

建立如下程序,并取名为course.awk:

{for(i=2;i<=NF;i++)Number[$i]++}

END{for(courseinNumber)printf("%10s%d\n",course,Number[course])}

执行下列命令:

$awk-fcourse.awkreg.dat

结果:

Graphics2

O.S.2

Discrete3

A.I.1

D.S.1

Arch.2

Algorithm2

说明:

Pattern{Actions}指令中END为awk之保留字,为Pattern的一种.END成立(其值为true)的条件是:

"awk处理完所有数据,即将离开程序时."平常读入数据行时,END并不成立,故其后的Actions并不被执行;唯有当awk读完所有数据时,该Actions才会被执行(注意,不管数据行有多少笔,END仅在最后才成立,故该Actions仅被执行一次.)

BEGIN与END有点类似,是awk中另一个保留的Pattern.唯一不同的是:

"以BEGIN为Pattern的Actions于程序一开始执行时,被执行一次."

awk程序中若含有以$开头的自定变量,都将以如下方式解释:

以i=2为例,$i=$2表第二个字段数据.(实际上,$在awk中为一运算符(Operator),用以取得字段数据.)

12.awk程序中使用shell命令:

awk程序中允许呼叫Shell指令.

例:

写一个awk程序来打印出线上人数.

将下列程序建文件,命名为count.awk

BEGIN{

while("who"|getline)n++

printn

}

并执行下列命令:

$awk-fcount.awk

结果:

显示在线人数.

说明:

awk程序并不一定要处理数据文件.以本例而言,仅输入程序文件count.awk,未输入任何数据文件.

BEGIN只在awk开始执行程序,尚未开启任何输入文件前,被执行一次.(注意:

只被执行一次).字符串"who"当成Shell上的命令,并将该命令送往Shell执行,执行的结果(原先应于屏幕印出者)则藉由pipe送进awk程序中.

getline为awk所提供的输入指令.其语法如下:

语法由何处读取数据数据读入后置于

getlinevar

getlinevarpipe变量变量var(var省略时,表示置于$0)

getlinevar见注一变量var(var省略时,表示置于$0)

注:

当Pattern为BEGIN或END时,getline将由stdin读取数据,否则由awk正处理的数据文件上读取数据.

getline一次读取一行数据,若读取成功则return1,若读取失败则return-1,若遇到文件结束(EOF),则return0;

本程序使用getline所return的数据来做为while判断循环停止的条件,某些awk版本较旧,并不容许使用者改变$0之值.这种版的awk执行本程序时会产生Error,读者可于getline之后置上一个变量(如此,getline读进来的数据便不会被置于$0),或直接改用gawk便可解决.

awk程序应用实例:

本节将示范一个统计上班到达时间及迟到次数的程序.这程序每日被执行时将读入二个文件:

员工当日到班时间的数据文件(如下列之arr.dat)

存放员工当月迟到累计次数的文件.

当程序执行执完毕后将更新第二个文件的数据(迟到次数),并打印当日的报表.这程序将分成下列数小节逐步完成,其大纲如下:

(1)在到班资料文件arr.dat之前增加一行抬头"IDNumberArrvialTime",并产生报表输出到文件today_rpt1中.

(2)将today_rpt1上的数据按员工代号排序,并加注执行当日日期;产生文件today_rpt2.

(3)将awk程序包含在一个shellscript文件中.

(4)于today_rpt2每日报表上,迟到者之前加上"*",并加注当日平均到班时间;产生文件today_rpt3.

(5)从文件中读取当月迟到次数,并根据当日出勤状况更新迟到累计数.

 

某公司其员工到勤时间档如下,取名为arr.dat.文件中第一栏为员工代号,第二栏为到达时间.本范例中,将使用该文件为数据文件.

10347:

26

10257:

27

11017:

32

10067:

45

10127:

46

10287:

49

10517:

51

10297:

57

10427:

59

10088:

01

10528:

05

10058:

12

13.重定向输出到文件:

>(输出到一个新产生的文件)或>>(添加输出的数据到文件末尾).

例:

在到班数据文件arr.dat之前增加一行抬头"IDNumberArrivalTime",并产生报表输出到文件today_rpt1中.

建立如下文件并取名为reformat1.awk:

BEGIN{print"IDNumberArrivalTime">"today_rpt1"

print"===========================">"today_rpt1"

}

{printf("%s%s\n",$1,$2)>"today_rpt1"}

执行:

$awk-freformat1.awkarr.dat

结果:

将产生文件today_rpt1,其内容如下:

IDNumberArrivalTime

============================

10347:

26

10257:

27

11017:

32

10067:

45

10127:

46

10287:

49

10517:

51

10297:

57

10427:

59

10088:

01

10528:

05

10058:

12

说明:

awk程序中,文件名称today_rpt1的前后须以"括住,表示today_rpt1为一字符串常量.若未以"括住,则today_rpt1将被awk解释为一个变量名称.

在awk中任何变量使用之前,并不须事先声明.其初始值为空字符串(Nullstring)或0.因此程序中若未以"将today_rpt1括住,则today_rpt1将是一变量,其值将是空字符串,这会在执行时造成错误.

14.awk中利用系统资源:

例:

将数据按员工ID排序后再输出到文件today_rpt2,并于表头附加执行时的日期.

分析:

awk程序中pipe可接受下列两种语法:

(1)awkoutput指令|"Shell接受的命令"(如:

print$1,$2|"sort-k1")

(2)"Shell接受的命令"|awkinput指令 (如:

"ls"|getline).

注:

awkinput指令只有getline一个.awkoutput指令有print,printf()二个.

(1)语法中,awk所输出的数据将转送往Shell,由Shell的命令进行处理.以上例而言,print所输出的数据将经由Shell命令"sort-k1"排序后再送往屏幕(stdout).

上列awk程序中,"print$1,$2"可能反复执行很多次,其输出的结果将先暂存于pipe中,等到该程序结束时,才会一并进行"sort-k1".

注:

不论print$1,$2被执行几次,"sort-k1"的执行时间是"awk程序结束时","sort-k1"的执行次数是"一次".

 

(2)语法中,awk将先调用Shell命令.其执行结果将通过pipe送入awk程序,以上例而言,awk先让Shell执行"ls",Shell执行后将结果存于pipe,awk指令getline再从pipe中读取数据.

awk"立刻"调用Shell来执行"ls",执行次数是一次.getline则可能执行多次(若pipe中存在多行数据).

建立如下文件并取名为reformat2.awk:

#程序reformat2.awk

#这程序用以练习awk中的pipe

BEGIN{

"date"|getline#Shell执行"date".getline取得结果并以$0记录

print"Todayis",$2,$3>"today_rpt2"

print"=========================">"today_rpt2"

print"IDNumberArrivalTime">"today_rpt2"

close("today_rpt2")

}

{printf("%s%s\n",$1,$2)|"sort-k1>>today_rpt2"}

执行如下命令:

$awk-freformat2.awkarr.dat

执行后,系统会自动将sort后的数据追加到文件today_rpt2末端.

结果:

Todayis 09月21日

=========================

IDNumberArrivalTime

10058:

12

10067:

45

10088:

01

10127:

46

10257:

27

10287:

49

10297:

57

10347:

26

10427:

59

10517:

51

10528:

05

11017:

32

awk提供另一个调用Shell命令的方法,即使用awk函数system("shell命令")例如:

$awk'

BEGIN{

system("date>date.dat")

getline<"date.dat"

print"Todayis",$2,$3

}

但使用system("shell命令")时,awk无法直接将执行中的部分数据输出给Shell命令.且Shell命令执行的结果也无法直接输入到awk中(可采用中间文件存储).

15.执行awk程序:

将awk程序直接写在shellscript之中.此后使用者执行awk程序时,就不需要每次都键入"awk-fprogramdatafile".

建立一个简单的awk程序mydump.awk,如下:

{print}

print之后未接任何参数时,表示"print$0".

若欲执行该awk程序,来印出文件today_rpt1及today_rpt2的内容时,执行下列命令:

方式一:

awk-fmydump.awktoday_rpt1today_rpt2

方式二:

awk'{print}'today_rpt1today_rpt2第二种方式系将awk程序直接写在Shell的命令行上,这种方式仅适合较短的awk程序.

方式三:

建立如下之shellscript,并取名为mydisplay:

#!

/bin/sh

#注意以下的awk与'之间须有空白隔开

awk'

{print}

'$*

#注意以上的'与$*之间须有空白隔开

执行mydisplay之前,须先将它改成可执行的文件(此步骤往后不再赘述).请执行如下命令:

$chmod+xmydispaly

往后使用者就可直接把mydisplay当成指令,来display任何文件,例如:

$./mydisplaytoday_rpt1today_rpt2

说明:

在script文件mydisplay中,指令"awk"与第一个'之间须有空格(Shell中并无"awk'"指令).

第一个'用以通知Shell其后为awk程序.第二个'则表示awk程序结束.故awk程序中一律以"括住字符串或字符,而不使用',以免Shell混淆.

$*为shellscript中的用法,它可用来代表命令行上"mydisplay之后的所有参数".例如:

$mudisplaytoday_rpt1today_rpt2

事实上Shell已先把该指令转换成:

awk'

{print}

'today_rpt1today_rpt2

本例中,$*用以代表"today_rpt1today_rpt2".在Shell的语法中,可用$1代表第一个参数,$2代表第二个参数.当不确定命令行上的参数个数时,可使用$*表之.

awk命令行上可同时指定多个数据文件,例如:

$awk-fdump.awktoday_rpt1today_rpt2

某些awk程序"仅"包含以BEGIN为Pattern的指令.执行这种awk程序时,awk并不须开启任何数据文件.此时命令行上若指定一个不存在的数据文件,并不会产生"无法打开文件"的错误.

awk会将Shell命令行上awk程序(或-f程序文件名)之后的所有字符串,视为将输入awk进行处理的数据文件文件名.

若执行awk的命令行上"未指定任何数据文件文件名",则将stdin视为输入之数据来源,直到输入endoffile(Ctrl-D)为止.可利用这个特点,设计可与awk即时聊天的程序.

 

16.改变awk切割字段的方式及自定义函数:

awk不仅能自动分割字段,也允许使用者改变其字段切割方式以适应各种格式之需要.使用者也可自定义函数,若有需要可将该函数单独写成一个文件,以供其它awk程序调用.

例:

若八点为上班时间,请加注"*"于迟到记录之前,并计算平均上班时间.

注:

awk中字符串"26"与数字26并无差异,可直接做字符串或数学运算,这是awk重要特色之一.

方法一:

对到达时间($2)d:

dd或dd:

dd进行字符串运算,分别取出到达的小时数及分钟数.

length(字符串):

返回该字符串的长度.

substr(字符串,起始位置,长度):

返回从起始位置起,指定长度之子字符串.若未指定长度,则返回从起始位置到字符串末尾的子字符串. 则:

小时数=substr($2,1,length($2)-3)

分钟数=substr($2,length($2)-2)

方法二:

字段分隔字符FS(fieldseperator)是awk的内建变量,其默认值是空白及tab.awk每次切割字段时都会先参考FS的内容.若把":

"也当成分隔字符,则awk便能自动把小时数及分钟数分隔成不同的字段.故令FS="[\t:

]+"(注:

[\t:

]+为一RegularExpression).

RegularExpression中使用中括号[...]表示一个字符集合,用以表示任意一个位于两中括号间的字符.故可用"[\t:

]"表示一个空白,tab或":

".

RegularExpression中使用"+"形容其前方的字符可出现一次或一次以上.故"[

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 经管营销

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1