前言
本文并不是一篇gawk手册一样的文章,所以不可能条理清楚的告诉你如何使用,而是循序渐进的描述自己对这个工具的掌握。
gawk表现的更像一门语言,像使用一门语言那样的使用它的基本操作就能达到我自己的需求了。
1. 拆分、选择
我们大概什么时候使用gawk呢?就我自己来说,就是对一个文件的每一行按照分隔符拆分成多个元素,然后选取自己需要的,即拆分、选择。
例如下面的一个文件test.file(姓名:学号:成绩)
Alice:1:98
Bob:2:70
使用gawk程序的基本格式:gawk option program file
option
->-F:
:指定分隔符,通过:
将每一行分隔
program
->'{print $1}'
:打印出分隔出来的元素1
file
->test.file
:指定输入文件,如果未指定,则从STDIN等待输入
renz@renz-ubuntu:~/work$ gawk -F: '{print $1}' test.file
Alice
Bob
renz@renz-ubuntu:~/work$ gawk -F: '{print $2}' test.file
1
2
renz@renz-ubuntu:~/work$ gawk -F: '{print $3}' test.file
98
70
gawk以文件的每行为一个单位,Alice:1:98
被:
分为Alice
、1
、98
,拆分的元素可以通过$1、$2、$3取出。
2. 多重拆分、选择
得益于可以在程序中使用多个命令命令1 | 命令2
,我们可以对已经拆分的结果再次拆分,这使我可以应对稍复杂的内容。
例如class.xml文件:
<class>
<students>
<student>
<name>Alice</name>
<serial>1</serial>
<score>98</score>
</student>
<student>
<name>Bob</name>
<serial>2</serial>
<score>70</score>
</student>
</students>
</class>
我想打印出所有同学的名字,策略就是先通过name
分隔为< >Alice</ >
即$1=' <',$2='>Alice<',$3='>'
renz@renz-ubuntu:~/work$ gawk '{FS="name"; print $2}' class.xml
>Alice</
>Bob</
然后对$2通过>
分隔为$1='',$2='Alice<'
renz@renz-ubuntu:~/work$ gawk '{FS="name"; print $2}' class.xml | gawk '{FS=">"; print $2}'
Alice</
Bob</
然后再对$2通过<
分隔为$1='Alice',$2=''。
renz@renz-ubuntu:~/work$ gawk '{FS="name"; print $2}' class.xml | gawk '{FS=">"; print $2}' | gawk '{FS="<"; print $1}'
Alice
Bob
3. 变量与循环结构的使用
3.1 为什么要使用变量
上一例中的xml文件完美到强迫症的人都会觉得舒服,因为是专门排版给人看的,未经过排版的class2.xml文件如下:
<class>
<students>
<student><name>Alice</name><serial>1</serial><score>98</score></student><student><name>Bob</name><serial>2</serial><score>70</score></student>
</students>
</class>
这个文件的结构对于使用xpath解析来说没有任何影响,但是对于使用gawk解析的我来说
renz@renz-ubuntu:~/work$ gawk '{FS="name"; print $2}' class2.xml | gawk '{FS=">"; print $2}' | gawk '{FS="<"; print $1}'
Alice
Bob不见了!
原因在于第二次解析的时候,Bob在$4中,而我们只解析了$2。
renz@renz-ubuntu:~/work$ gawk '{FS="name"; print $1,$2,$3,$4,$5}' class2.xml
<class>
<students>
<student><serial>1</serial>< >Alice</ ></student><student><serial>2</serial>< >Bob</ ></student>
</students>
</class>
于是我们只要改变策略就可以了:
学生数 | 解析的参数 |
---|---|
1 | $2 |
2 | $2,$4 |
3 | $2,$4,$6 |
... | ... |
n | $2,$4,...,$2n |
但是<student>是一个可以无限制添加的节点啊,每多一个学生就要修改一下程序吗?
在工作中我遇到这种情况的时候,内心是崩溃的。于是经验不足的我产生了一个大胆的想法,gawk能不能够告诉我它究竟分隔了多少个元素,这样我就可以通过循环来确定每次要解析的元素。
我就是这样查到了gawk的高级特性。
3.2 如何使用变量
两种不同类型的变量:
- 内建变量
- 自定义变量
3.2.1 内建变量
字段和记录分隔符变量
内建变量是用来使用程序里的特定功能的,解决诸如我们用什么来分隔字符串,再以怎样的格式显示出来。
变量 | 描述 |
---|---|
FS | 输入字段分隔符 |
OFS | 输出字段分隔符(默认空格) |
数据变量
用来掌控环境变化的,还可以提取shell环境的信息。
变量 | 描述 |
---|---|
ARGC | 命令行参数个数 |
ARGV | 包含命令行参数的数组 |
FILENAME | 用作gawk输入数据的数据文件的文件名 |
NF | 数据文件中的字段总数 |
还记得我最开始的需求吗,我需要知道按照分隔符到底分了多少个字段,这样我就可以根据分隔的字段总数来选取解析的参数,NF
就可以帮助我完成这件事。我们只需解析偶数,一直解析到NF-1
就能不管一行有多少,都能遍历取出了:
renz@renz-ubuntu:~/work$ awk '{FS="name"; i=2;while (i<NF){ print $i;i++;i++} }' class2.xml | gawk '{FS=">"; print $2}'
Bob</
然而出了点问题,太尴尬了,毕竟我也是新手。但是上面的例子同时展示了两个新的特性——自定义变量
与循环结构
,这就是为什么我们可以把他当作一门语言来学的原因,对了,后面将学到还可以声明函数:)。
网友评论