Chinaunix首页 | 论坛 | 博客
  • 博客访问: 33175
  • 博文数量: 20
  • 博客积分: 385
  • 博客等级: 一等列兵
  • 技术积分: 220
  • 用 户 组: 普通用户
  • 注册时间: 2008-06-02 19:40
文章分类

全部博文(20)

文章存档

2016年(12)

2011年(2)

2009年(2)

2008年(4)

我的朋友

分类: LINUX

2009-11-04 10:08:37

 

1 awk起步

awk基本的功能是寻找那些文件中包含有特定pattern的行(或者文本单元)。当某行匹配到其中一个pattern的时候,awk对这一行执行指定的动作。Awk对输入的所有行保持这种处理方式直到到达文件的末尾。

awk中的程式不同于其他语言中的程式,因为awk程式是数据驱动的;也就是说你描述要处理什么样的数据和找到后对它们做什么。大多数其它语言是过程的;你需要描述,非常详细地,程式要做的每一步。当利用过程语言工作的时候,一般情况下你要清楚地描述要处理的数据时很困难的。基于此,awk程式都非常容易阅读和书写。

运行awk时,你要指定一个awk程式来告知awk去做什么。这种程式由一些列规则(rules)组成。(它也可能包含功能定义,一种高级的特性)。每个规则指定一个要寻找的pattern和找到后执行的动作。

句法上,规则包含一个pattern和其后的动作描述。动作描述由大括号包围用以与pattern分开。新行分开各个规则。因此,awk程式看起来是这样的:

pattern { action }

pattern { action }

1.1如何运行awk程式

有很多途径运行awk程式。假如程式短的话,在命令行中用awk命令运行它是最简单的,像下边这样:

awk 'program' input-file1 input-file2 ...

当程式长的时候,一般方便的做法是将程式放在一个文件中,然后用如下的命令运行:

awk -f program-file input-file1 input-file2 ...

本部分讨论这两种情况,和各个变种形式。

1.1.1单步简单awk程式

一旦你熟悉awk,你会在想用的时候经常输入简单的程式。那么,你可以书写程式让它作为awk命令的第一个参数,运行它:

awk 'program' input-file1 input-file2 ...

其中,program由一系列的模式(pattern)和执行动作(action)组成。

这个命令格式指示shell或者命令解释器,运行awk并且利用program去处理文件中的记录(行)。用单引号将program括起,避免使shellawk的字符解释成特殊的shell字符。单引号同样使shell将整个program看成是awk的一个参数,且允许program可以超过一行长。

这种格式对通过shell脚本运行短的或者中长型的awk程式也有用,因为它避免了awk程式对分离的文件的需求。独立的shell脚本有很好的可依赖性,因为没有文件错放的问题。1.1.2 运行没有输入文件的awk程式

也可以运行没有任何输入文件的awk命令。如果输入如下命令:

awk 'program'

awk 应用program于标准输入,通常意味着任何你通过终端输入的东西。这持续到你用输入ctrl-d来指示输入结束。(在其它操作系统中,可能不一样,ctrl-z)。

来看一个例子,下边的程式打印一个友好的提示,来使你不用担心计算机编程的复杂性:

awk "BEGIN { print \" Don't Panic!\" } "

->Don"t Panic!

这个程式没有读取任何输入。双引号前的字符'\'是必须的,因为shell的引号规则—尤其是因为它混合了单引号和双引号。

下边的例子模仿cat的功能;它复制任何你用键盘输入的字符到标准输出。

Awk '{print}'

1.1.3 运行长程式

有时候你的awk程式可能很长。这种情况下,将程式放在单独的文件中是很方便的。为了告知awk使用这个文件最为它的program,可以输入:

awk -f source-file input-file1 input-file2 ...

-f 指示awk程序从source-file中获取program。例如,我们可以把

BEGIN { print "Don't Panic!" }

放入文件advice中,然后命令:

awk -f advice

做了前述相同的事情。

注意到在advice中,awk程式米有单引号包括。引号只用于在awk命令行中运行的程式。

1.1.4 可执行的awk程式

一旦你学习了awk,你可能希望写独立的awk脚本,利用'#!'脚本机制。你可以在很多UNIX系统和GNU系统上这样做。例如,可以如下更行文件advice

#! /bin/awk -f

BEGIN { print "Don't Panic!" }

独立的awk脚本在你写一个别人可以调用的程式而别人不知道它使用awk语言的时候是有用的。

1.1.5 awk程式中的注释

awk语言中,注释开始于'#',持续到行尾。'#'没必要是该行的第一个字符,awk语言忽略行中'#'以后的字符。

1.1.6 shell引号问题

awk "BEGIN {print \" ' \"}" #-' 打印'

awk 'BEGIN {print "\\"}' #-\ 打印 \

1.2 实例用到的数据文件

本文档中很多实例用到两个输入文件。第一个,BBS-list,代表一列电子公告牌系统及其信息。第二个,inventory-shipped包含了月度船运信息。两个文件中,每一行被认为是一个记录。

文件 BBS-list中,每一条记录包括公告牌名字,电话号码,牌子波特率和运转时间。最后一列'A'标示24小时操作,'B'标示只能在晚上和周末,'C'标示只能在周末操作。

          aardvark 555-5553 1200/300 B

          alpo-net     555-3412     2400/1200/300     A
     barfly       555-7685     1200/300          A
     bites        555-1675     2400/1200/300     A
     camelot      555-0542     300               C
     core         555-2912     1200/300          C
     fooey        555-1234     2400/1200/300     B
     foot         555-6699     1200/300          B
     macfoo       555-6480     1200/300          A
     sdace        555-3430     2400/1200/300     A
sabafoo      555-2127     1200/300          C
数据文件 inventory-shipped代表一年中的船运信息。每一记录包含字段月份,绿色箱子数目,红色箱子数目,橘黄色袋子数目,蓝色包数目。总共有16项纪录,包括去年的12个月份和今年的4个月。
Jan  13  25  15 115
     Feb  15  32  24 226
     Mar  15  24  34 228
     Apr  31  52  63 420
     May  16  34  29 208
     Jun  31  42  75 492
     Jul  24  34  67 436
     Aug  15  34  47 316
     Sep  13  55  37 277
     Oct  29  54  68 525
     Nov  20  87  82 577
     Dec  17  35  61 401
    
     Jan  21  36  64 620
     Feb  26  58  80 652
     Mar  24  75  70 495
Apr  21  70  74 514
1.3 一些简单的例子
接下来的命令运行一个简单的awk程式,它从输入文件BBS-list中寻找字符串'foo'
awk ' /foo/ { print $0 } ' BBS-list
当包含有'foo'的行被发现,它们将被打印出来,因为'print $0'表示打印当前行。(只是单独的'print'表示同样的行为,所以我们也可以这样代替。)
你可能已经注意到了斜线号'/'包围着'foo',斜线号指示'foo'是要寻找的模式(pattern)。这种模式被称为正则表达式。模式被允许匹配与一个字的一部分。用单引号括起awkprogram可以禁止shell将它的任何部分解释成shell字符。
awk的规则中,模式(pattern)或者动作描述可以被省略,但是不能同时。如果模式被省略,动作行为将作用于每一个输入行。如果动作描述被省略,默认的动作是打印匹配模式的每一行。
因此,我们在上一个例子中可以省去动作描述(打印语句和花括号),结果是一样的:所有匹配行将被打印出来。对比一下,省去打印语句但是保留花括号会产生一个空动作,标示什么都不做(也就是说,没有行被打印)。
很多使用的awk程式只有一两行。下边的是一些有用的,但是短小的程式的一个集合。大多是例子用到一个数据文件叫data。这只是个占位符。
打印出最长输入行的长度:
awk ' { if (length($0) > max) max = length($0) }
END { print max } ' data
打印出长度大于80个字符的行:
awk ' length($0) > 80 ' data
打印出data中最长行的长度:
expand data | awk ' { if (x < length()) x = length() }
END { print "maximum line length is " x } '
打印出至少含有一个字段你的行:
awk ' NF > 0' data
打印出0100之间的7个随机数:
awk ' BEGIN { for (i=1; i <= 7; i++)
print int(101 * rand()) }'
打印出files使用的总的字节数:
ls -l files  | awk ' { x+= $5 }
END { print " total bytes: " x } '
打印一个对所有用户登录名字的一个排序列表:
awk -F: ' { print $1 } ' /etc/passwd | sort
打印文件的行数:
awk ' END { print NR } ' data
打印文件中的偶数行:
awk ' NR % 2 == 0 ' data
1.4 双规则样例
awk应用每次从输入文件中读入一行。对于每一行,awk对每一个规则的模式进行尝试。如果有多个模式匹配,相应的动作描述将按顺序被执行。
1.5 一个更复杂的例子
既然我们已经熟练了简单的任务,让我们看看典型的awk程式做些什么。这个例子展示了awk怎样被用于汇总,选择,重新排列其他应用的输出内容:
ls -l | awk ' $6 == "Nov" { sum += $5 }
END { print sum }'
这条命令打印出当前文件夹中被最后修改于11月份的问价你的总共字节数。
1.6 awk 语句对比行
通常,awk程式中的每一行是一个单独的语句或者单独的规则,如下:
awk ' /12/ { print $0 }
/21/ { print $0 }  BBS-list  inventory-shipped
然而,gawk忽略任何下边的符号和关键字后边的新行:
, { ? : || && do else
新行(\n?)在任何地方被认为是语句的结束。
如果你想将一个语句分开两行书写,而新行符终结一个语句,你可以继续语句通过用反斜线'\'结束第一行。反斜线一定要作为行的最后一个字符。如例子:
awk ' /This regular expression is too long,so continue it\
on the next line/ { print $1 } '

2 正则表达式

正则表达式(regexp)是描述一组字符串的一个途径。
一个正则表达式被斜线符号'/'括起,它是awk模式,去匹配文本包含这个集合的所有输入行。最简单的正则表达式是一序列字母,数字,或者两者兼备。这样一种正则表达式匹配任何包含这个序列的字符串。因此,正则表达式 'foo' 匹配任何包含有字符序列'foo'的字符串。
也就是,模式'foo'匹配任何输入记录,无论在这记录的任何位置出现字符序列'foo'。其他种类的正则表达式能让你描述更加复杂的字符串。
2.1 如何使用正则表达式
一个正则表达式可以被包括与斜线符号中作为模式。然后这个正则表达式会被测试于整个输入文本的每一记录。(正常情况下,只需要匹配文本的某些部分)。例如,下边的例子打印出任何地方包含有'foo' 的记录的第二个字段:
	awk ' /foo/ { print $2 } ' 	BBS-list
~(波浪号),~和正则表达式也可以被用于匹配表达式。

2.2 转义序列
一些字符不能原义地包含在字符串常量(如foo)或者正则表达式(如/foo/)中。代替之,它们应该用转义序列表示,这是一种以反斜线\开始的字符序列。转义序列的一种使用是在字符串中包含双引号字符。因为平常的双引号结束串,所以你一定要用' \" '去表示一个实在的双引号字符作为串的一部分。例如:
	awk 'BEGIN { print "He said \"hi!\" to her." }'
	-->He said "hi!" to her.
阅读(1478) | 评论(0) | 转发(0) |
0

上一篇:归去来兮辞

下一篇:初试mpg123

给主人留下些什么吧!~~