awk则是基于列的文本处理工具,它的工作方式是按行读取文本并视为一条记录,每条记录以字段分割成若干字段,然后输出各字段的值。事实上,awk是一种编程语言,其语法异常复杂,所以awk也是一种较难掌握的文本处理工具。本节将使用大量的例子来直接演示awk的常见用法,让读者能迅速学会使用。awk认为文件都是结构化的,也就是说都是由单词和各种空白字符组成的,这里的“空白字符”包括空格、Tab,以及连续的空格和Tab等。每个非空白的部分叫做“域”,从左到右依次是第一个域、第二个域,等等。 $1、$2分别用于表示域,$0则表示全部域。

为了演示awk的用法,首先创建文件Awk.txt,文件内容如下所示:

[root@localhost ~]# cat Awd.txt
john.wang       Male    30      021-11111111
lucy.yang       Female  25      021-22222222
jack.chen       Male    35      021-33333333
lily.gong       Female  20      021-44444444 ShangHai

打印指定域

既然awk使用$1、$2代表不同的域,则可以打印指定域。拿Awk.txt的第一行来说,第一个域为john.wang,第二个域为Male,第三个域为30,第四个域为021-11111111。在下面的演示中,第一条命令打印了$1、$4这两个域,而第二条命令则打印了全部的域。

#只打印姓名和电话号码
[root@localhost ~]# awk '{print $1,$4}' Awd.txt
john.wang 021-11111111
lucy.yang 021-22222222
jack.chen 021-33333333
lily.gong 021-44444444
#打印全部内容
[root@localhost ~]# awk '{print $0}' Awd.txt
john.wang       Male    30      021-11111111
lucy.yang       Female  25      021-22222222
jack.chen       Male    35      021-33333333
lily.gong       Female  20      021-44444444    ShangHai

指定打印分隔符

默认情况下awk是使用空白字符作为分隔符的,但是也可以通过-F参数指定分隔符,来区分不同的域(有点像之前学过的cut命令)。示例如下:

#指定“.”作为分隔符,这样每一行的$1就是“.”之前的字符,$2就是“.”之后的字符
比如说第一行的$1是“john”,$2是“Male    30      021-11111111”
[root@localhost ~]# awk-F. '{print $1,$2}' Awd.txt
john wang       Male    30      021-11111111
lucy yang       Female  25      021-22222222
jack chen       Male    35      021-33333333
lily gong       Female  20      021-44444444    ShangHai

内部变量NF

文件Awk.txt所包含的内容并不多,所以我们很容易地知道它的前3行中每行都有4个域,而最后一行是5个域。但是如果有时候文件很大,每行列数都不一样,靠观察就不现实了,必须通过特定的方式来获得文件的列数。通过awk的内部变量NF可以简单地做到这点。当然,如果你指定了不同的分隔符,结果可能不一样。示例如下:

#使用默认分隔符
[root@localhost ~]# awk '{print NF}' Awd.txt
4
4
4
5
#指定分隔符
[root@localhost ~]# awk-F. '{print NF}' Awd.txt
2
2
2
2

 打印固定域

通过内部变量可以简单地得到每行的列数,而如果在NF之前加上$符号,则代表“最后一列”,这样不管每行有多少列,只要使用$NF就能打印出最后一行。如果是倒数第二行呢?读者可以先思考一下再看示例。

#打印最后一行
[root@localhost ~]# awk '{print $NF}' Awd.txt
021-11111111
021-22222222
021-33333333
ShangHai
#用$(NF-1)打印倒数第二行

[root@localhost ~]# awk '{print $(NF-1)}' Awd.txt
30
25
35
021-44444444

截取字符串

可以使用substr()函数对指定域截取字符串,该函数的基本使用方法如下:

substr(指定域,第一个开始字符的位置,第二个结束的位置)
#其中第二个结束的位置可以为空,这样默认输出到该域的最后一个字符

下例中将输出Awk.txt文件第一个域的第六个字符到最后一个字符的内容:

#该例中,第二个结束位置省略,所以结束位置为第一个域的最后一个字符
[root@localhost ~]# cat Awd.txt | awk '{print substr($1,6)}'
wang
yang
chen
gong

 确定字符串的长度

使用内部变量length可以确定字符串的长度,示例如下:

[root@localhost ~]# cat Awd.txt | awk '{print length}'
30
32
30
41

使用awk求列和

结构化的数据在系统中是随处可见的,比如用ls-l命令得到的输出、各类系统日志等。在日常工作中,经常有将其中的数据进行相加的需求。下面演示了对所有人的年龄进行的一些计算。请注意,年龄字段是第三个域:

#求年龄的和
[root@localhost ~]# cat Awd.txt | awk 'BEGIN{total=0}{total+=$3}END{print total}'
110
#求平均年龄
[root@localhost ~]# cat Awd.txt | awk 'BEGIN{total=0}{total+=$3}END{print total/NR}'
27.5

 

10-07 15:03