初识gawk, gawk Notes(1)

第一次看见awk这三个字母,是在某实习童鞋的QQ状态里面,赞同事写的awk如何高效。

昨天在书畅草草看了下IBM官方技术博里的文章,觉得很赞,很激动,但是有点看不太懂,还是自己抱着教科书,老老实实从头看起吧。

哦,这里说一下,最近看的shell相关的东西,都是跟着《A Pratical Guide to Linux Commands,Editors, and Shell Programming》这本书的。

gawk是awk的GNU版本。

> 使用条件

主要是用gawk来处理结构化的数据。

什么是结构化呢,我的理解,就是一个文件里面的内容,可以按照某种记录记录格式,一条记录一条记录地读,同时,每一条记录中间用一个分隔符分成了若干个部分,而且所有记录用同一个分隔符,且所有行用分隔符分出来的部分的数目相同。

当然,gawk可以结构化数据,也可以输出结构化数据。

另外,要提的一点是,gawk在处理数据的时候,不修改原有的数据文件,只是将数据读出来,做处理。

> 语法

gawk [option] [program] [file-list]

gawk [options] –f program-file [file-list]

白话说来,运行gawk有两种方式:

1、直接在shell里面运行。option是运行的选项;program是gawk的代码,要用' ' 括起来,目的是屏蔽shell对里面内容的解析;file-list是用到的数据文件。[option 有哪些?file-list多个文件怎么处理?]

2、将gawk作为独立的文件,调用gawk文件来执行。要用-f来标记是使用的gawk文件,同时program-list是gawk文件的列表。

> 选项(option)

仅列出要紧的几个

-F fs 将fs作为输入字段分隔符
-f program-file 从program-file 命名文件而不是标准输入读取gawk程序,用户可以多次指定这个选项
-v var=value 将value赋值给var。赋值动作在gawk程序执行之前进行,并用于BEGIN模式。可以在命令行上多次指定这一选项。

> 组成单元

好吧,这是我根据自己理解用的一个名词。为什么这么说呢?想想以前的各种语言,C,基本组成单元是函数,除了头文件之外,程序是有各个函数构成的;C++类似;Java,各种方法,所以说,他们的组成单元是 函数 或 方法。

但是gawk呢?如下:

pattern{ action }

每个action用 "{","}"包围起来,同时,"{"要跟在pattern的同一行

pattern有多种,action各式各样,但是整个gawk的程序,可以按照这样的组成单元,分解开来。

所以说,写gawk程序,就是在源文件里面,构建一个个这样的组成单元。

gawk的组成单元,有两个部分,pattern,action。pattern作为一个模式,决定了action在什么情况下运行,而action,则是当记录符合条件(pattern)时,执行什么样的动作。这里想用一个图来说明下:

image

图1 gawk处理结构化数据示意图

如图1所示,gawk的程度,就像是在结构数据上的套子,顺着结构数据,从头读到尾,然后根据数据是否满足要求,来决定执行action。这里有一个问题,在gawk文件内,多个组成单元,是怎么样的一个执行顺序,在后面会用实例检验一下。

根据pattern的不同,可以讲组成单元分成3类:

1、系统默认

有两个BEGIN,END。

BEGIN在所有代码开始前执行,也就是说,他不参与pattern的判定。主要是用来初始化一些系统变量等。

END在前面的所有代码执行完毕后执行,也没有pattern的判定。主要是清理一些中间生成的临时数据等等。

2、无pattern

也就是pattern为空,表示所有的结构化数据,每行数据,都要执行这个pattern下的action

3、定义pattern

实际上“定义pattern”和“无pattern”一样,action都是用户来写的,这里之所以区分开,如前面所说,是基于pattern来分的。

这一类,pattern可以是一个条件判断,也可以是一个正则表达式匹配。

> 系统变量

这些变量被gawk占用了,用的时候,直接拿来就是对应的含义:

表1 变量

$0 当前记录(作为单个变量)
$1-$n 当前记录中的字段
FILENAME 当前输入文件名
FS (Field Split)输入字段字段分隔符
NF (Number of Fields)当前记录的字段数目
NR (Number of current Record)当前记录的记录编号
OFS (Output Field Split)输出字段分隔符(默认为空格)
ORS (Output Record Split)输出记录分隔符(默认为换行符)
RS (Record Split)输入记录分隔符(默认为换行)

FS,RS,可以在BEGIN中,根据具体输入文件的不同,进行设置。

OFS,ORS,也可以再BEGIN中,根据输出文件的要求,进行设置。

在程序中,可以通过NF,知道一条记录中有多少个字段,也就决定了$1-$n的n是多少。

任何时刻都可以修改分隔符的值,具体方法是通过在程序中或者在命令行中使用--assign(-v)选项,将一项新的值指派给对应的变量。

(也就意味着,在输入和输出文件中,都可以出现分隔符不同一的情况)

> 函数

gawk的内置函数,用来操作数字和字符串

表2 函数

length(str) 返回字符串str的字符个数,如果没有参数str,返回当前记录的字符个数
int(num) 返回num的整数部分
index(str1,str2) 返回str2在str1中的位置,如果str2不存在返回0
split(str,arr,del) 用del做分隔符,将str的元素放置到arr[1]到arr[n]中,返回数组元素个数
sprintf(fmt,args) 根据fmt格式化args并返回格式化后的字符串
substr(str,pos,len) 返回str中从pos开始长度为len个字符的字符串
tolower(str) str字母全部转为小写
toupper(str) str字母全部转为大写

> 注释

该行以 # 开头。

> 关联数组

我理解它类似于C#的Dictionary<k,v>,可以用字符串做索引:array[string]=value

在使用的时候,利用for可以实现:for (elem in array) print array[elem]

> 控制结构

if-else,while,for 与C语言的对应项基本一致,完全不同于Shell下的对应项,不再赘述。

 

初始gawk,就到这里,用一个例子来结束:

数据文件cars记录了一组关于汽车的销售信息(品牌,型号,生产年代,千里里程数,价格),用gawk,写程序,统计下平均使用年限,所有车的平均价格和新车(晚于2000年)的平均价格

image

图2 数据文件cars

image

图3 gawk代码

image

图4 运行结果

posted @ 2012-09-04 00:28  郝玉琨  阅读(3057)  评论(0编辑  收藏  举报