linux之awk基础

第一章

1.awk 简介

awk不仅仅时linux系统中的一个命令,而且是一种编程语言,可以用来处理数据和生成报告(excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。本章主要讲解awk命令的运用。

 

2.awk 的格式

  • awk指令是由模式,动作,或者模式和动作的组合组成。
  • 模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。
  • 动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。比如awk使用格式
  • pattern既模式,也可以理解为条件。
  • action既动作,可以理解为干啥,找到人之后你要做什么

3.awk 内置变量

ARGC               命令行参数个数
ARGV               命令行参数排列
ENVIRON            支持队列中系统环境变量的使用
FILENAME           awk浏览的文件名
FNR                浏览文件的记录数
FS                 设置输入域分隔符,等价于命令行 -F选项
NF                 浏览记录的域的个数
NR                 已读的记录数
OFS                输出域分隔符
ORS                输出记录分隔符
RS                 控制记录分隔符

 此外,$0变量是指整条记录。$1表示当前行的第一个域,$2表示当前行的第二个域,......以此类推。

 

第二章 实战

[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print NR,$1}' /etc/passwd
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10{print $1}' /etc/passwd
lp
sync
shutdown
halt
mail
operator
[root@bogon ~]#

命令解释

-F 分隔符:  

NR >=5 && NR<=10 这部分表示模式,是一个条件,表示取第5行到第10行。

{print NR,¥1} :表示输出行号和$1第一列

2. 只有模式

[root@bogon ~]# awk -F ":" 'NR>=5 && NR<=10' /etc/passwd
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin

 

命令解释:

这里少了动作:{print NR,$1} 所以就输出了 NR>=5 &&NR<=10 第5 -10 行

3. 只有动作

[root@bogon ~]# awk -F':' '{print NR,$1}' /etc/passwd
1 root
2 bin
3 daemon
4 adm
5 lp
6 sync
7 shutdown
8 halt
9 mail
10 operator
11 games
12 ftp
13 nobody
14 systemd-network

命令说明:
-F指定分隔符为冒号
这里没有条件,表示对每一行都处理
{print NR,$1}表示动作,显示NR行号与$1第一列
这里要理解没有条件的时候,awk会处理每一行。

4.多个模式和动作

[root@bogon ~]# awk -F":" 'NR==1{print NR,$1}' /etc/passwd
1 root
[root@bogon ~]# awk -F":" 'NR==1{print NR,$1}NR==2{print NR,$NF}' /etc/passwd
1 root
2 /sbin/nologin
[root@bogon ~]#

命令解释:

-F 以冒号为分隔符

这里有多个条件与动作的组合
NR==1表示条件,行号(NR)等于1的条件满足的时候,执行{print NR,$1}动作,输出行号与第一列。
NR==2表示条件,行号(NR)等于2的条件满足的时候,执行{print NR,$NF}动作,输出行号与最后一列($NF)

 

5.文件处里过程

[root@bogon ~]# awk 'NR>=2{print NR,$0}' /test/files/awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 operator:x:11:0:operator:/root:/sbin/nologin
[root@bogon ~]#

 

命令说明:
条件NR>=2,表示行号大于等于2时候,执行{print $0}显示整行。
awk是通过一行一行的处理文件,这条命令中包含模式部分(条件)和动作部分(动作),awk将处理模式(条件)指定的行

6.awk 小结

1)awk读入第一行内容

2)判断是否符合模式中的条件NR>=2

a,如果匹配则执行对应的动作{print $0}
b,如果不匹配条件,继续读取下一行

3)继续读取下一行
4)重复过程1-3,直到读取到最后一行(EOF:end of file)

第三章

1.记录和字段

接下来我给大家带来两个新概念记录和字段,这里为了方便大家理解可以把记录就当作行即记录==行,字段相当于列,字段==列。

名称含义
record 记录,行
field

域,区域,字段,列

 

2.

[root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:

命令解释

在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些\n(回车换行符),\n也是字符哦。

 

 

[root@bogon ~]# awk 'BEGIN{RS="/"}{print NR,$0}' /test/files/awkfile.txt
1 root:x:0:0:root:
2 root:
3 bin
4 bash
bin:x:1:1:bin:
5 bin:
6 sbin
7 nologin
daemon:x:2:2:daemon:
8 sbin:

命令说明:
在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。
我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束
在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些\n(回车换行符),\n也是字符哦。

 

对$0的认识

  • 如1.7.2的例子,可以看出awk中$0表示整行,其实awk使用$0来表示整条记录。记录分隔符存在RS变量中,或者说每个记录以RS内置变量结束。
  • 另外,awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录,NR的值就会自动+1
  • 行(记录):默认以\n(回车换行)结束。而这个行的结束不就是记录分隔符嘛。
  • 所以在awk中,RS(记录分隔符)变量表示着行的结束符号(默认是回车换行).

 

[root@chensiqi1 ~]# awk '{print NR,$0}' /server/files/awkfile.txt
1 root:x:0:0:root:/root:/bin/bash
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6 sync:x:5:0:sync:/sbin:/bin/sync
7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8 halt:x:7:0:halt:/sbin:/sbin/halt
9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
10 uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin

命令说明:
NR既number of record,当前记录的记录号,刚开始学也可以理解为行号。
$0表示整行或者说整个记录

 

 第4章

实战1

[root@bogon ~]# echo "I am test,my qq is 222222">>/test/files/test.txt
[root@bogon ~]# cat /test/files/test.txt
I am test,my qq is 222222
[root@bogon ~]# awk -F "[ ,]" '{print $3,$NF}' /test/files/test.txt
test 222222
[root@bogon ~]# awk -F "[,]" '{print $3,$NF}' /test/files/test.txt
 my qq is 222222
[root@bogon ~]#

 

命令解释:
通过命令-F参数指定区域分隔符
[ ,]是正则表达式里面的内容,它表示一个整体,“一个”字符,既空格或者逗号(,),合并在一起,-F “[ ,]”就表示以空格或者逗号(,)为区域分隔符

 

第5章

awk默认就支持的元字符:

元字符功能示例解释
^ 字符串开头 /^chensiqi/或$3~/^chensiqi/ 匹配所有以chensiqi开头的字符串;匹配出所有第三列中以chensiqi开头的
$ 字符串结尾 /chensiqi$/或$3~/chensiqi$/ 匹配所有以chensiqi结尾的字符串;匹配第三列中以chensiqi结尾的
.(点) 匹配任意但个字符(包括回车符) /c..l/ 匹配字母c,然后两个任意字符,再以l结尾的行
* 重复0个或多个前一个字符 /a*cool/ 匹配0个或多个a之后紧跟着cool的行
+ 重复前一个字符一次或多次 /a+b/ 匹配一个或多个a加上字符串b的行
? 匹配0个或一个前边的字符 /a?b/ 匹配以字母a或b或c开头的行
[] 匹配指定字符组内的任一个字符 /^[abc]/ 匹配以字母a或b或c开头的行
[^] 匹配不在指定字符组内的任一字符 /^[^abc]/ 匹配不以字母a或b或c开头的行
() 子表达式组合 /(chensiqi)+/ 表示一个或多个cool组合,当有一些字符需要组合时,使用括号括起来
| 或者的意思 /(chensiqi)|B/ 匹配chensiqi或字母B的行

awk默认不支持的元字符:(参数--posix)

元字符功能示例解释
x{m} x字符重复m次 /cool{5}/ 匹配l字符5次
x{m,} x字符重复至少m次 /(cool){2,}/ 匹配cool整体,至少2次
x{m,n} x字符重复至少m次,但不超过n次 /(cool){5,6}/ 匹配cool整体,至少5次,最多6次

提示:

  • 加括号代表整体匹配,不加那么就匹配前边的一个字符。awk默认不支持这种形式的正则,需要加--posix参数或者--re-interval
  • 正则表达式的运用,默认是在行内查找匹配的字符串,若有匹配则执行action操作,但是有时候仅需要固定的列来匹配指定的正则表达式,比如:我想取/etc/passwd文件中第五列{$5}这一列查找匹配mail字符串的行,这样就需要用另外两个匹配操作符,并且awk里面只有这两个操作符来匹配正则表达式。

实在1

[root@bogon ~]# awk -F":" '$0~/^root/' /test/files/awkfile.txt
root:x:0:0:root:/root:/bin/bash
[root@bogon ~]# cd /test/files/
[root@bogon files]# ls
awkfile.txt  count.txt  ip.txt  test.txt
[root@bogon files]# awk -F":" '/^root/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
[root@bogon files]#

命令解释

awk只用正则表达式的时候是默认匹配整行的即‘$0~/^root/’和‘/^root/’是一样的。

实战2

匹配其中某一行

 [root@bogon files]# awk -F ":" '$5~/shutdown/' awkfile.txt
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
[root@bogon files]#

 

第6章

文件测试

[root@bogon files]# cat >>/test/files/reg.txt<<KOF
> Zhang Dandan    41117397    :250:100:175
> Zhang Xiaoyu    390320151   :155:90:201
> Meng  Feixue    80042789    :250:60:50
> Wu    Waiwai    70271111    :250:80:75
> Liu   Bingbing  41117483    :250:100:175
> Wang  Xiaoai    3515064655  :50:95:135
> Zi    Gege      1986787350  :250:168:200
> Li    Youjiu    918391635   :175:75:300
> Lao   Nanhai    918391635   :250:100:175
> KOF

 

说明:

  • 第一列是姓氏
  • 第二列是名字
  • 第一列第二列合起来就是姓名
  • 第三列是对应的ID号码
  • 最后三列是三次捐款数量

 

2.2.7 awk正则表达式练习题

练习题1:显示姓Zhang的人的第二次捐款金额及她的名字

练习题2:显示Xiaoyu的名字和ID号码

练习题3:显示所有以41开头的ID号码的人的全名和ID号码

练习题4:显示所有以一个D或X开头的人名全名

练习题5:显示所有ID号码最后一位数字是1或5的人的全名

练习题6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135

练习题7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue

 

练习题1

示例1:显示姓Zhang的人的第二次捐款金额及她的名字

[root@bogon files]# awk -F "[ :]+" '$1~/^Zhang/{print $1,$2,$5}' reg.txt
Zhang Dandan 100
Zhang Xiaoyu 90
[root@bogon files]#

或者

awk -F "[ :]+" '$1~/^Zhang/{print $2,$(NF-1)}' reg.txt

说明:

  • -F指定分隔符,现在大家知道了-F即FS也是支持正则表达式的。
  • 【 :】+ 表示连续的空格或冒号
  • -F “【 :】+” 以连续的空格或冒号为分隔符
  • /Zhang/表示条件,整行中包含Dan字符的这个条件。
  • {print $1,$(NF-1)} 表示动作,满足条件后,执行显示第一列($1)和倒数第二列($(NF-1))当然$5也可以。

注意:
NF是一行中有多少列,NF-1整行就是倒数第二列。
$(NF-1)就是取倒数第二列内容。

练习题二

练习题2:显示Xiaoyu的名字和ID号码

[root@bogon files]# awk '/Xiaoyu/{print $1,$3}' reg.txt
Zhang 390320151
[root@bogon files]#

或者

 awk -F "[ :]+" '$2~/^Xiaoyu/{print $1,$3}' reg.txt

命令说明:
指定分隔符-F “【:】+”
$2~/Xiaoyu/表示条件,第二列包含Xiaoyu时候执行对应的动作
{print $1,$3}表示动作,显示第一列和第三列的内容

 

练习三

练习题3:显示所有以41开头的ID号码的人的全名和ID号码

[root@bogon files]# awk '$0~/41/' reg.txt
Zhang Dandan    41117397    :250:100:175
Liu   Bingbing  41117483    :250:100:175
[root@bogon files]# awk '$0~/41/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
[root@bogon files]# awk '$3~/41/{print $1,$2,$3}' reg.txt
Zhang Dandan 41117397
Liu Bingbing 41117483
[root@bogon files]#

 

练习题4:显示所有以一个D或X开头的人名全名

[root@bogon files]# awk -F "[ :]+" '$2~/^D|^X/{print $1,$2}' reg.txt
Zhang Dandan
Zhang Xiaoyu
Wang Xiaoai
[root@bogon files]#

命令说明:
-F “【 :】+”指定分隔符
|表示或,^以...开头

 

示例5:显示所有ID号码最后一位数字是1或5的人的全名

[root@bogon files]# awk '$3~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
[root@bogon files]# awk -F"[ :]+" '$3~/1$|5$/{print $1,$2}' reg.txt
Zhang Xiaoyu
Wu Waiwai
Wang Xiaoai
Li Youjiu
Lao Nanhai
[root@bogon files]#

示例6:显示Xiaoyu的捐款,每个值都有以$开头。如$520$200$135

[root@bogon files]# awk -F"[ :]+" '$2~/Xiaoyu/{print "$"$4"$"$5"$"$6}' reg.txt
$155$90$201
[root@bogon files]#

示例7:显示所有人的全名,以姓,名的格式显示,如Meng,Feixue

[root@bogon files]# awk  '{print $1","$2}' reg.txt
Zhang,Dandan
Zhang,Xiaoyu
Meng,Feixue
Wu,Waiwai
Liu,Bingbing
Wang,Xiaoai
Zi,Gege
Li,Youjiu
Lao,Nanhai
[root@bogon files]#

实例8 :取出网卡eth0的ip地址

[root@bogon files]# ip addr |awk -F "[ /]+"  'NR==9{print $3}'
192.168.1.111
[root@bogon files]#

 

第7章

正侧扩展

[root@bogon files]# echo "---===1###2"
---===1###2
[root@bogon files]# echo "---===1###2" |grep "[-=#]"
---===1###2
[root@bogon files]# echo "---===1###2" |grep -o "[-=#]"
-
-
-
=
=
=
#
#
#
[root@bogon files]#

awk正则之{} -花括号

awk中的花括号有些不常用,但是偶尔会用到这里简单介绍。

示例:取出awkfile中第一列包含一个o或者两个o的行

[root@bogon files]# awk -F":" '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
operator:x:11:0:operator:/root:/sbin/nologin
[root@bogon files]#

 

[root@bogon files]# awk -F: --re-interval '$1~/o{1,2}/' awkfile.txt
root:x:0:0:root:/root:/bin/bash
daemon:x:2:2:daemon:/sbin:/sbin/nologin
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
operator:x:11:0:operator:/root:/sbin/nologin

 

2.实例

取出常用的服务端口

[root@bogon files]# awk -F "[ /]+" '$1~/^(ssh)$|^(http)$|^(https)$|^(mysql)$|^(ftp)$/{print $1,$2}' /etc/services |sort |uniq
ftp 21
http 80
https 443
mysql 3306
ssh 22
[root@bogon files]#

  • |是或者的意思,正则表达式
  • sort是将输出结果排序
  • uniq是去重复但不标记重复个数
  • uniq -c去重复但标记重复个数

 

 实例3

说明:
条件:从第三列以bin开头字符串的行到第三列以lp开头字符串的行
动作:显示行号和整行

[root@bogon files]# awk '/^bin/,NR==5{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

 

示例4

awk -F":" '$5~/^bin/,/^lp/{print NR,$0}' awkfile.txt
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 daemon:x:2:2:daemon:/sbin:/sbin/nologin
4 adm:x:3:4:adm:/var/adm:/sbin/nologin
5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

说明:
条件:从第五列以bin开头的行到以lp开头的行
动作:显示行号和正航内容
合起来:从第三列以bin开始的行到以lp开头的行并显示其行号和整行内容

 

第九章

BEGIN 用法

[root@bogon files]# awk -F":" 'BEGIN{print "username","UID"}{print $1,$3}' awkfile.txt
username UID   ##这就是输出的表头信息
root 0
bin 1
daemon 2
adm 3
lp 4
sync 5
shutdown 6
halt 7
mail 8
operator 11
[root@bogon files]#

说明:
要在第一行输出一些username和UID,我们应该想到BEGIN{}这个特殊的条件(模式),因为BEGIN{}在awk读取文件之前执行的。
所以结果是BEGIN{print "username","UID"},注意print命令里面双引号吃啥吐啥,原样输出。
然后我们实现了在输出文件内容之前输出“username”和“UID”,下一步输出文件的第一列和第三列即{print $1,$3}
最后结果就是BEGIN{print "username","UID"}{print $1,$3}

 2/使用BEGIN模块的特殊性质,进行一些测试。

[root@www files]#简单输出内容: [root@www files]# awk 'BEGIN{print "hello world!"}'
hello world!
[root@www files]# #进行计算
[root@www files]# awk 'BEGIN{print 10/3}'
3.33333
[root@www files]# awk 'BEGIN{print 10/3+1}'
4.33333
[root@www files]# awk 'BEGIN{print 10/3+1/4*9}'
5.58333
[root@www files]# #和变量有关的操作
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b}'
1 2
[root@www files]# awk 'BEGIN{a=1;b=2;print a,b,a+b}'
1 2 3

 

企业案例:统计/etc/servies文件里的空行数量

思路:
a)空行通过正则表达式来实现:^$
b)统计数量:

  • grep -c
  • awk

方法一:grep

grep "^$" /etc/services | wc -l
16
 grep -c "^$" /etc/services
16

说明:
grep命令-c表示count计数统计包含^$的行一共有多少。

方法二:

 awk '/^$/{i++}END{print i}' /etc/services 
16

提示:
使用了awk的技术功能,很常用
第一步:统计空行个数
/^$/表示条件,匹配出空行,然后执行{i++}(i++等于i=i+1)即:/^$/{i=i+1}

我们可以通过/^$/{i=i+1;print i}来查看awk执行过程

wk '/^$/{i=i+1;print "the value of i is:"i}' /etc/services 
the value of i is:1
the value of i is:2
the value of i is:3
the value of i is:4
the value of i is:5
the value of i is:6
the value of i is:7
the value of i is:8
the value of i is:9
the value of i is:10
the value of i is:11
the value of i is:12
the value of i is:13
the value of i is:14
the value of i is:15
the value of i is:16

第二步:输出最后结果

  • 但是我们只想要最后的结果16,不想要过程怎么办?使用END模式输出结果
  • 因为END模式的特殊性质所以很适合输出最终结果

所以最终结果就是awk '/^$/{i=i+1}END{print "blank lines count:"i}' /etc/services

awk编程思想:

  1. 先处理,最后再END模块输出
  2. {print NR,$0}body模块处理,处理完毕后
  3. END{print "end of file"}输出一个结果

企业面试题5:文件count.txt,文件内容是1到100(由seq 100生成),请计算文件每行值加起来的结果(计算1+...+100)

思路:
文件每一行都有且只有一个数字,所以我们要让文件的每行内容相加。
回顾一下上一道题我们用的是i++即i=i+1
这里我们需要使用到第二个常用的表达式
i=i+$0

对比一下,其实只是把上边的1换成了$0

awk '{i=i+$0}END{print i}' count.txt 
5050

 

posted @ 2018-10-08 15:41  Mr.zou  阅读(327)  评论(0编辑  收藏  举报