一、AWK概述

AWK的内容也太多了,简单的做一个复习,都差点闪了老腰!

awk的作用就是取列、取列并计算,当我们一想到取列或者取列计算的时候就应当立马想到 awk,另外,awk还相当不要脸的包揽了它二弟和它三弟的部分工作,让我很是焦灼,在我使用的时候不知道用哪个好!

AWK的用户与sed的用法相似,它的语法是这样的:

awk <选项> '找谁{干啥}' #一定要注意引号是英文的单引号

awk的选项其实比较少,常用就是-F,用来指定分隔符,最有亮点的地方是分隔符竟然可以指定多个!!!

//大于号可以换成大于、大于等于、小于、小于等于,等于
[root@centos7 ~]# awk 'NR>=2{print}' /etc/passwd

// 打印出第三行的第二列
//awk默认以一个或连续多个空格,TAB,连续多个TAB为分隔符,所以这里面不指定分隔符,默认就是以空格为分隔符的。
ip a s ens33 | awk 'NR==3{print $2}'
192.168.80.200/24
ifconfig eth0 | awk 'NR==2{print $2}'
192.168.80.2

//指定使用空格和斜线为分隔符,指定多个分隔符,并指定了次数,一次或多次,也就说使用了[]之后,连续之意失效了,需要手动通过扩展的正则表达式加号强调。
[root@centos7 ~]# ip a s ens33 | awk ‐F'[ /]+' 'NR==3{print $3}'
192.168.80.200

  

使用awk的注意点:

二、行与列

行操作

NRnumber is recored的缩写,其实就是行号的意思,如上面 的例子所示。

$0代表的是一整行,$1代表的就不是第一行了,$1代表的就是第一列,其实我们把$0理解成所有列就很自然了,END代表的最后一列,我们下面有例子。

//如果不指定是第一行NR==1,它默认就会把文件里面的第一列全部给你打印出来
[root@centos7 ~]# awk ‐F':' 'NR==1{print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/bash

//END代表最后一行,打印最后一行,{print $0}是默认的,即使不写,效果也是一样的。
[root@centos7 ~]# awk 'END{print $0}' /etc/passwd
zhanghe:x:1000:1000:zhanghe:/home/zhanghe:/bin/bash

//你看,不加'$0',效果是一样的,END(print $0) 相当于 END (print)
[root@centos7 ~]# awk 'END{print}' /etc/passwd
zhanghe:x:1000:1000:zhanghe:/home/zhanghe:/bin/bash #sed ‐n '$p sed也可以实现这样的效果

那如果我想要第2行以后的行呢?就正常写就行,如下

1 [root@centos7 ~]# awk 'NR>=2{print}' /etc/passwd 

行号也可以单独的使用,比如我想显示出/etc/passwd的行号,也就说想要实现cat -n /etc/passwdless -N /etc/passwd的功能

[root@centos7 ~]# awk '{print NR}' /etc/passwd #这样仅把所有的行号打印出来了
1
2
3
4
……
//在行号后面再加一个$0,$0啥意思还记得吗?代表所有列,行号加上显示所有列就会有cat ‐n的效果了。
[root@centos7 ~]# awk '{print NR,$0}' /etc/passwd
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

其实,sed能做取行操作,awk也能做,比如:

1 [root@centos7 ~]# sed ‐n 2p /etc/passwd #打印第二行
2 bin:x:1:1:bin:/bin:/sbin/nologin
3 [root@centos7 ~]# awk 'NR==2{print}' /etc/passwd #打印第二行
4 bin:x:1:1:bin:/bin:/sbin/nologin

列操作

上述例子当中的“$数字”的意思其实就是取哪一列,‘print $3’其实就是取第3列,如果 我们想取多列呢?比如我想取出/etc/passwd文件文件当中第1列和第3列,怎么搞呢?

//取最后一行的第一列和最后三列
[root@centos7 ~]# awk ‐F':' 'END{print $1,$3}' /etc/passwd
zhanghe 1000

那如果我们想取最后一列呢?我们知道END代表最后一行,最后一列用NF来表示,如下所 示:

1 [root@centos7 ~]#awk -F':' 'END{print $NF}' /etc/passwd
2 /bin/bash

取最后一列,会用到什么地方呢?比如,日志文件,/var/log/secure文件下的日志的长度并不是固定的,在取日志记录的最后一部分的时候,我们可以用到取最后一列。 那取倒数第二列呢?

1 [root@centos7 ~]# awk ‐F':' 'NR==1{print $NF‐1}' /etc/passwd #这样写不行,需要加上一个括号,如下所示:
2 ‐1
3 [root@centos7 ~]# awk ‐F':' 'NR==1{print $(NF‐1)}' /etc/passwd
4 /root
5 [root@centos7 ~]# echo 66 77 88 | awk '{print $NF‐1}'
6 87
7 [root@centos7 ~]# echo 66 77 88 | awk '{print $(NF‐1)}'
8 77

其实取列的时候还可以进行比较呢?比如 ,我想要找到/etc/passwd当中第三列大于500的 行。

1 [root@centos7 ~]# awk ‐F':' '$3>500{print $0}' /etc/passwd #后面的{print$0}是可以省略的。

三、取磁盘的使用率--案例

案例一:显示磁盘使用率大于10%的分区和挂载点

[root@centos7 ~]# df ‐h | awk '$5>10%' #列比较的时候不能识别%号
awk: cmd. line:2: $5>10%
awk: cmd. line:2: ^ unexpected newline or end of string
[root@centos7 ~]# df ‐h | awk '$5>10' #不加%,会不准,你看,下面把8%的也显示
出来了,下面有解释
文件系统 容量 已用 可用 已用% 挂载点
/dev/mapper/centos_centos7‐root 50G 3.9G 47G 8% /
/dev/sda1 1014M 179M 836M 18% /boot
[root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10{print $1,$NF}' #通过sed把%全都删除
文件系统 挂载点
/dev/sda1 /boot
[root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10{print $1,$NF}' | tai
l ‐1 #这样的结果就正常了。
/dev/sda1 /boot

为什么会出现不准的情况?其实并不是不准,LINUX系统不会骗我们的,只不过,它默认不是按照我们以为的方式在比大小,如下所示:

[root@centos7 ~]# seq 10 #生成10个数
1
2
3
4
5
6
7
8
9
10
[root@centos7 ~]# seq 10 | sort #使用sort对它们进行排序,结果2比10大?这是怎么回事?是因为linux在比较大小的时候默认是按位进行比较的,
13 1
14 10
15 2
16 3
17 4
18 5
19 6
20 7
21 8
22 9
23 [root@centos7 ~]# seq 10 | sort ‐n #加一个‐n的参数,就是按照数字的大小进行排序,你看,这又恢复正常了。
24 1
25 2
26 3
27 4
28 5
29 6
30 7
31 8
32 9
33 10

如果问题再难一点,显示出磁盘使用率大于10%且小于50%的磁盘分区和挂载点呢?就用 &&符号就行,&&就是并且的意思嘛!如下所示:

1 [root@centos7 ~]# df ‐h | sed 's@%@@g' | awk '$5>10&&$5<50{print $1,$NF}'
| tail ‐1
2 /dev/sda1 /boot

我们在看行的时候也可以使用,我们我们想看第三行到第六行中间的行:

1 [root@centos7 ~]# awk 'NR>3&&NR<6{print NR,$0}' /etc/passwd
2 4 adm:x:3:4:adm:/var/adm:/sbin/nologin
3 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
1 [root@centos7 ~]# sed ‐n '4,5p' /etc/passwd
2 adm:x:3:4:adm:/var/adm:/sbin/nologin
3 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin

四、正则表达式

做为条件我们上面在描述条件的时候都是用的行号,其实我们还可以使用正则表达式做为条件。 比如1:过滤出包含数字的行

1 [root@centos7 test.dir]# cat test.txt
2 zhanghe
3 zhanghe6
4 [root@centos7 test.dir]# awk '/[0‐9]/' test.txt #awk在使用正则表达式做为条件的时候要用//号的,sed也是这样,完整的写法是这样的'/[0‐9]/{print $0}'
5 zhanghe6
6 [root@centos7 test.dir]# grep '[0‐9]' test.txt
7 zhanghe6

比如2:过滤出/etc/passwd当中开头是root一直到结尾是shutdown之间的行

[root@nginx ~]# sed -n '/^root/,/shutdown$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
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

[root@nginx ~]# awk '/^root/,/shutdown$/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
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

比如3:过滤出/etc/passwd当中开关是root一直到结尾是shutdown之间的行的最后一列

[root@nginx ~]# awk -F: '/^root/,/shutdown$/ {print $NF}' /etc/passwd
/bin/bash
/sbin/nologin
/sbin/nologin
/sbin/nologin
/sbin/nologin
/bin/sync
/sbin/shutdown

比如4:显示出最后一列是bash的用户名,下面这个最是骚气,直接指定去匹配哪一个列 

1 [root@centos7 ~]# awk ‐F':' '$NF~/bash$/{print $1}' /etc/passwd
2 root
3 zhanghe

五、范围做为条件

比如1:显示以一个z或者一个r开头的用户名

1 [root@centos7 ~]# awk ‐F':' '$1~/^(r|z)/{print $1}' /etc/passwd #也可以这样写:awk ‐F':' '$1~/^[rz]/{print $1}'
2 root
3 rpc
4 rtkit
5 radvd
6 rpcuser
7 zhanghe

注意:^在grepsed当中只能表示以什么什么开头的行,在awk当中可以通过前而的列表示某一列当中以什么开头的行,也就是说范围增加了。 比如2:显示UID号码最为一位是1或是5的全名

1 [root@centos7 ~]# awk ‐F':' '$3~/[15]$/{print $1}' /etc/passwd
2 bin
3 sync
4 operator
5 dbus
6 pulse
7 radvd
8 unbound
9 setroubleshoot
1 [root@centos7 ~]# awk ‐F':' '{print $3,$4}' /etc/passwd | head ‐4
2 0 0
3 1 1
4 2 2
5 3 4
6 [root@centos7 ~]# awk ‐F':' '{print "#"$3"#"$4}' /etc/passwd | head ‐4 #可以在里面加点东西,要用双引号才可以,双引号里面有什么,就会原封不动的显示什么。
7 #0#0
8 #1#1
9 #2#2
10 #3#4

用awk做sed的替换功能 用gsub函数,用法:{gsub (/:/,"$")} 将双竖线的内容替换为双引号里面的内容

1 [root@centos7 ~]# awk '{gsub (/:/,"$");print}' /etc/passwd | head ‐4
2 root$x$0$0$root$/root$/bin/bash
3 bin$x$1$1$bin$/bin$/sbin/nologin
4 daemon$x$2$2$daemon$/sbin$/sbin/nologin
5 adm$x$3$4$adm$/var/adm$/sbin/nologin
1 [root@centos7 ~]# awk '{gsub (/r/,"R") $1;print}' /etc/passwd | head ‐4 #精确替换哪一列的什么
2 Root:x:0:0:Root:/Root:/bin/bash
3 bin:x:1:1:bin:/bin:/sbin/nologin
4 daemon:x:2:2:daemon:/sbin:/sbin/nologin
5 adm:x:3:4:adm:/vaR/adm:/sbin/nologin
6 [root@centos7 ~]# awk '{gsub (/:/,"$");print}' /etc/passwd | head ‐4 #不指定哪一列就是一整行,相当于$0,也就是所有列
7 root$x$0$0$root$/root$/bin/bash
8 bin$x$1$1$bin$/bin$/sbin/nologin
9 daemon$x$2$2$daemon$/sbin$/sbin/nologin
10 adm$x$3$4$adm$/var/adm$/sbin/nologin

显示人名和UID,然后以逗号分隔,就用最简单的方式即可

1 [root@centos7 ~]# awk ‐F':' '{print $1,$3}' /etc/passwd | head ‐4
2 root 0
3 bin 1
4 daemon 2
5 adm 3
6 [root@centos7 ~]# awk ‐F':' '{print $1","$3}' /etc/passwd | head ‐4
7 root,0
8 bin,1
9 daemon,2
10 adm,3

六、BEGIN和END

记住:

  1. BEGIN里面的内容会在awk读取文件之前执行,一般来用计算。

  2. END里面的内容会有awk读取文件之后执行,一般用来做统计。

BEGIN:

1 [root@centos7 ~]# awk 'BEGIN{print 1+2,1‐8}'
2 3 ‐7
3 [root@centos7 ~]# awk ‐F':' 'BEGIN{OFS="$$$"}{print $1,$2}' /etc/passwd |
head ‐4 #也可以用来修改变量,相当于上面讲的‐v OFS
4 root$$$x
5 bin$$$x
6 daemon$$$x
7 adm$$$x

END: 什么时候用END?统计的时候,先进行计算,最后END()显示最后结果,其实这才是 awk最重要的功能,awk原名文本报名生成器,用来生成报告用的,生成报告的话一定会用 到统计了。

"!!!!"}' /etc/passwd | tail ‐4 #这个例子主要体会一下END的内容会在读取文件内容之
后执行。
2 ntp$$$x
3 tcpdump$$$x
4 zhanghe$$$x
5 !!!!

再来一个例子: 统计/etc//services 文件当中空行的数量 i=i+1 相当于i++ 用来出现的总次数,初始值是0. 

1 [root@centos7 tmp]# awk '/^$/{i++;print i}' /tmp/test.sh #有5个空行,这不是我想要的结果
2 1
3 2
4 3
5 4
6 5
1 [root@centos7 tmp]# awk '/^$/{i++}END{print i}' /tmp/test.sh #完成之后再打开出变量i,这里的变量i已经增长到5了,这时候打印出来正合适呢!
2 5

求和:i=i+$,相当于i+=$

和:i=i+$,相当于i+=$
1 [root@centos7 tmp]# cat test.txt
2 12
3 11
4 14
5 [root@centos7 tmp]# awk '{sum += $1};END{print sum}' test.txt #对第一列进行求和
6 37
1 [root@centos7 tmp]# cat test.txt
2 12 45
3 11 11
4 14 13
5 [root@centos7 tmp]# awk '{sum += $2};END{print sum}' test.txt #对第二列进行求和
6 69
1 [root@centos7 tmp]# cat test.txt
2 aaa 12 45
3 aaa 11 11
4 aaa 14 13
5 bbb 1 2
6 [root@centos7 tmp]# awk '/aaa/{sum += $3}END{print sum}' test.txt #对符号条件的行进行求和
7 69

 

上 

12-18 04:25