Chinaunix首页 | 论坛 | 博客
  • 博客访问: 233344
  • 博文数量: 84
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 451
  • 用 户 组: 普通用户
  • 注册时间: 2013-04-05 13:45
个人简介

IT!

文章分类
文章存档

2013年(84)

我的朋友

分类: LINUX

2013-10-05 19:43:24

原文地址:管理脚本语言gawk--连载3 作者:顽主

gawk


    awk是一种程序语言,对文档资料的处理具有很强的功能。awk名称是由它三个最初设计者的姓氏的第一个字母而命名的:AlfredV.Aho、PeterJ.Weinberger、BrianW.Kernighan。
    awk最初在1977年完成。1985年发表了一个新版本的awk,它的功能比旧版本增强了不少。awk能够用很短的程序对文档里的资料做修改、比较、提取、打印等处理。如果使用C或Pascal等语言代码编写完成上述的任务会十分不方便而且很花费时间,所写的程序也会很大。
    awk不仅仅是一个编程语言,它还是Linux系统管理员和程序员的一个不可缺少的工具。
    awk语言本身十分好学,易于掌握,并且特别的灵活。
    gawk是GNU计划下所做的awk,gawk最初在1986年完成,之后不断地被改进、更新。gawk包含awk的所有功能。

    基本上有两种方法可以执行gawk程序。
    如果gawk程序很短,则可以将gawk直接写在命令行,如下所示:
        gawk'program'input-file1input-file2...
其中program包括一些pattern和action。

    如果gawk程序较长,较为方便的做法是将gawk程序存在一个文件中,gawk的格式如下所示:
        gawk-fprogram-fileinput-file1input-file2...
    gawk程序的文件不止一个时,执行gawk的格式如下所示:
        gawk-fprogram-file1-fprogram-file2...input-file1input-file2...

文件、记录和字段


    一般情况下,gawk可以处理文件中的数值数据,但也可以处理字符串信息。如果数据没有存储在文件中,可以通过管道命令和其他的重定向方法给gawk提供输入。当然,gawk只能处理文本文件(ASCII码文件)。电话号码本就是一个gawk可以处理的文件的简单例子。电话号码本由很多条目组成,每一个条目都有同样的格式:姓、名、地址、电话号码。每一个条目都是按字母顺序排列。

    在gawk中,每一个这样的条目叫做一个记录。它是一个完整的数据的集合。例如,电话号码本中的SmithJohn这个条目,包括他的地址和电话号码,就是一条记录。记录中的每一项叫做一个字段。在gawk中,字段是最基本的单位。多个记录的集合组成了一个文件。大多数情况下,字段之间由一个特殊的字符分开,像空格、TAB、分号等。这些字符叫做字段分隔符。请看下面这个/etc/passwd文件:

tparker;t36s62hsh;501;101;TimParker;/home/tparker;/bin/bash
etreijs;2ys639dj3h;502;101;EdTreijs;/home/etreijs;/bin/tcsh
ychow;1h27sj;503;101;YvonneChow;/home/ychow;/bin/bash

    你可以看出/etc/passwd文件使用分号作为字段分隔符。/etc/passwd文件中的每一行都包括七个字段:用户名;口令;用户ID;工作组ID;注释;home目录;启始的外壳。如果你想要查找第六个字段,只需数过五个分号即可。但考虑到以下电话号码本的例子,你就会发现一些问题:

SmithJohn13WilsonSt.555-1283
SmithJohn2736ArtsideDrApt123555-2736
SmithJohn125WestmountCr555-1726

    虽然我们能够分辨出每个记录包括四个字段,但gawk却无能为力。电话号码本使用空格作为分隔符,所以gawk认为Smith是第一个字段,John是第二个字段,13是第三个字段,依次类推。就gawk而言,如果用空格作为字段分隔符的话,则第一个记录有六个字段,而第二个记录有八个字段。所以,我们必须找出一个更好的字段分隔符。例如,像下面一样使用斜杠作为字段分隔符:

Smith/John/13WilsonSt./555-1283
Smith/John/2736ArtsideDr/Apt/123/555-2736
Smith/John/125WestmountCr/555-1726

    如果你没有指定其他的字符作为字段分隔符,那么gawk将缺省地使用空格或TAB作为字段分隔符。

模式和动作


    在gawk语言中每一个命令都由两部分组成:一个模式(pattern)和一个相应的动作(action)。只要模式符合,gawk就会执行相应的动作。其中模式部分用两个斜杠括起来,而动作部分用一对花括号括起来。例如:

/pattern1/{action1}
/pattern2/{action2}
/pattern3/{action3}

    所有的gawk程序都是由这样的一对对的模式和动作组成的。其中模式或动作都能够被省略,但是两个不能同时被省略。如果模式被省略,则对于作为输入的文件里面的每一行,动作都会被执行。如果动作被省略,则缺省的动作被执行,既显示出所有符合模式的输入行而不做任何的改动。

    下面是一个简单的例子,因为gawk程序很短,所以将gawk程序直接写在外壳命令行:
gawk'/tparker/'/etc/passwd
    此程序在上面提到的/etc/passwd文件中寻找符合tparker模式的记录并显示(此例中没有动作,所以缺省的动作被执行)。

    让我们再看一个例子:
gawk'/UNIX/{print$2}'file2.data
    此命令将逐行查找file2.data文件中包含UNIX的记录,并打印这些记录的第二个字段。

    你也可以在一个命令中使用多个模式和动作对,例如:
gawk'/scandal/{print$1}/rumor/{print$2}'gossip_file
    此命令搜索文件gossip_file中包括scandal的记录,并打印第一个字段。然后再从头搜索gossip_file中包括rumor的记录,并打印第二个字段。

运算


    gawk有很多比较运算符,下面列出重要的几个:

==相等
!=不相等
>大于
<小于
>=大于等于
<=小于等于

例如:gawk'$4>100'testfile将会显示文件testfile中那些第四个字段大于100的记录。

    下表列出了gawk中基本的数值运算符。

运算符说明示例
+加法运算2+6
-减法运算6-3
*乘法运算2*5
/除法运算8/4
^乘方运算3^2(=9)
%求余数9%4(=1)

    例如:{print$3/2}显示第三个字段被2除的结果。
    在gawk中,运算符的优先权和一般的数学运算的优先权一样。例如:{print$1+$2*$3}显示第二个字段和第三个字段相乘,然后和第一个字段相加的结果。你也可以用括号改变优先次序。例如:{print($1+$2)*$3}显示第一个字段和第二个字段相加,然后和第三个字段相乘的结果。

内部函数


    gawk中有各种的内部函数,现在介绍如下:

sqrt(x)求x的平方根
sin(x)求x的正弦函数
cos(x)求x的余弦函数
atan2(x,y)求x/y的余切函数
log(x)求x的自然对数
exp(x)求x的e次方
int(x)求x的整数部分
rand()求0和1之间的随机数
srand(x)将x设置为rand()的种子数

index(in,find)在字符串in中寻找字符串find第一次出现的地方,返回值是字符串find出现在字符串in里面的位置。如果在字符串in里面找不到字符串find,则返回值为0。
例如:printindex("peanut","an")
显示结果3。

length(string)求出string有几个字符。
例如:length("abcde")
显示结果5。

match(string,regexp)在字符串string中寻找符合regexp的最长、最靠左边的子字符串。返回值是regexp在string的开始位置,即index值。match函数将会设置系统变量RSTART等于index的值,系统变量RLENGTH等于符合的字符个数。如果不符合,则会设置RSTART为0、RLENGTH为-1。
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)与前面的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。

输入输出的内部函数
close(filename)将输入或输出的文件filename关闭。
system(command)此函数允许用户执行操作系统的指令,执行完毕后将回到gawk程序。
例如:BEGIN{system("ls")}

字符串和数字


    字符串就是一连串的字符,它可以被gawk逐字地翻译。字符串用双引号括起来。数字不能用双引号括起来,并且gawk将它当作一个数值。
例如:gawk'$1!="Tim"{print}'testfile
此命令将显示第一个字段和Tim不相同的所有记录。如果命令中Tim两边不用双引号,gawk将不能正确执行。
再如:gawk'$1=="50"{print}'testfile
此命令将显示所有第一个字段和50这个字符串相同的记录。gawk不管第一字段中的数值的大小,而只是逐字地比较。这时,字符串50和数值50并不相等。

    我们可以让动作显示一些比较复杂的结果。例如:
gawk'$1!="Tim"{print$1,$5,$6,$2}'testfile

    你也可以使用一些换码控制符格式化整行的输出。之所以叫做换码控制符,是因为gawk对这些符号有特殊的解释。下面列出常用的换码控制符:

\a警告或响铃字符。
\b后退一格。
\f换页。
\n换行。
\r回车。
\tTab。
\v垂直的tab。

    在gawk中,缺省的字段分隔符一般是空格符或TAB。但你可以在命令行使用-F选项改变字符分隔符,只需在-F后面跟着你想用的分隔符即可。
gawk-F";"'/tparker/{print}'/etc/passwd
在此例中,你将字符分隔符设置成分号。注意:-F必须是大写的,而且必须在第一个引号之前。

元字符


    gawk语言在格式匹配时有其特殊的规则。例如,cat能够和记录中任何位置有这三个字符的字段匹配。但有时你需要一些更为特殊的匹配。如果你想让cat只和concatenate匹配,则需要在格式两端加上空格:
/cat/{print}

再例如,你希望既和cat又和CAT匹配,则可以使用或(|):
/cat|CAT/{print}

    在gawk中,有几个字符有特殊意义。下面列出可以用在gawk格式中的这些字符:

?^表示字段的开始。
例如:
$3~/^b/
如果第三个字段以字符b开始,则匹配。

?$表示字段的结束。
例如:
$3~/b$/
如果第三个字段以字符b结束,则匹配。

?.表示和任何单字符m匹配。
例如:
$3~/i.m/
如果第三个字段有字符i,则匹配。

?|表示“或”。
例如:
/cat|CAT/
和cat或CAT字符匹配。

?*表示字符的零到多次重复。
例如:
/UNI*X/
和UNX、UNIX、UNIIX、UNIIIX等匹配。

?+表示字符的一次到多次重复。
例如:
/UNI+X/
和UNIX、UNIIX等匹配。

?\{a,b\}表示字符a次到b次之间的重复。
例如:
/UNI\{1,3\}X
和UNIX、UNIIX和UNIIIX匹配。

??表示字符零次和一次的重复。
例如:
/UNI?X/
和UNX和UNIX匹配。

?[]表示字符的范围。
例如:
/I[BDG]M/
和IBM、IDM和IGM匹配

?[^]表示不在[]中的字符。
例如:
/I[^DE]M/
和所有的以I开始、M结束的包括三个字符的字符串匹配,除了IDM和IEM之外。

阅读(353) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~