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