一、AWK概述
AWK
的内容也太多了,简单的做一个复习,都差点闪了老腰!
awk
的作用就是取列、取列并计算,当我们一想到取列或者取列计算的时候就应当立马想到 aw
k,另外,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的注意点:
二、行与列
行操作
NR
是number 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/passwd
和less -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
注意:^在grep
和sed
当中只能表示以什么什么开头的行,在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
上