awk高级
awk高级
1. 工作流程
我们要注意的一点就是awk是一行一行处理的,并不是一下子就把一整列给取出来了。
打印列:
[root@dy1 ~]# cat test.txt
00 11 22
33 44 55
66 77 88
//$0代表一整行
[root@dy1 ~]# awk '{print $0}' test.txt
00 11 22
33 44 55
66 77 88
//NR的意思是行号
[root@dy1 ~]# awk '{print NR,$0}' test.txt
1 00 11 22
2 33 44 55
3 66 77 88
//打印第一列和第三列
[root@dy1 ~]# awk '{print $1,$3}' test.txt
00 22
33 55
66 88
//打印每一行有多少列
[root@dy1 ~]# awk '{print NF}' test.txt
3
3
3
//打印最后一列
[root@dy1 ~]# awk '{print $NF}' test.txt
22
55
88
//打印最后一列的数值减去1
[root@dy1 ~]# awk '{print $NF-1}' test.txt
21
54
87
//打印倒数第二列
[root@dy1 ~]# awk '{print $(NF-1)}' test.txt
11
44
77
[root@dy1 ~]# cat test.txt
00:11 22
33:44 55
66:77 88
//以:分隔,打印第二列
[root@dy1 ~]# awk -F":" '{print $2}' test.txt
11 22
44 55
77 88
//以空格分隔,打印第二列
[root@dy1 ~]# awk -F" " '{print $2}' test.txt
22
55
88
//以空格或者以冒号为分隔符打印
[root@dy1 ~]# awk -F"[ :]" '{print $1}' test.txt
00
33
66
分隔符:
//打印不规则的文本
[root@dy1 ~]# cat test.txt
00::11 22
33::44 55
66::77 88
//分隔符可以有多个,而且可以连接出现多次
[root@dy1 ~]# awk -F"[ :]+" '{print $1}' test.txt
00
33
66
[root@dy1 ~]# awk -F"[ :]+" '{print $NF}' test.txt
22
55
88
//FS相当于-F 指定什么为分隔符,使用-F实际就是修改FS
[root@dy1 ~]# cat test.txt
00::11 22
33::44 55
66::77 88
[root@dy1 ~]# awk 'BEGIN {FS="[ :]+"} {print $NF}' test.txt
22
55
88
[root@dy1 ~]# awk 'BEGIN {FS="[ :]+"} {print $1,$2}' test.txt
00 11
33 44
66 77
//默认打印时分隔符是以空格,可以通过OFS指定打印时的分隔符
[root@dy1 ~]# awk 'BEGIN {FS="[ :]+";OFS="@@"} {print $1,$2}' test.txt
00@@11
33@@44
66@@77
//小练习,分别用三剑客取出IP地址
[root@dy1 ~]# ip addr show eth0 | awk 'NR==3{print $2}' | sed -r 's@(^.*)\/24@\1@'
192.168.80.146
[root@dy1 ~]# ip addr show eth0 | awk 'NR==3{print $2}' | egrep -o '^.*/' | tr -d /
192.168.80.146
[root@dy1 ~]# ip addr show eth0 | awk 'NR==3{print $2}' | awk -F"/" '{print $1}'
192.168.80.146
NR与FNR
[root@dy1 ~]# cat test.txt
00::11 22
33::44 55
66::77 88
[root@dy1 ~]# cat /etc/issue
\S
Kernel \r on an \m
//用NR如果对两个文件操作的话,行号会延续
[root@dy1 ~]# awk 'BEGIN {FS="[ :]+";OFS="@@"} {print NR":"$1,$2}' test.txt /etc/issue
1:00@@11
2:33@@44
3:66@@77
4:\S@@
5:Kernel@@\r
6:@@
////用FNR如果对两个文件操作的话,行号不会延续
[root@dy1 ~]# awk 'BEGIN {FS="[ :]+";OFS="@@"} {print FNR":"$1,$2}' test.txt /etc/issue
1:00@@11
2:33@@44
3:66@@77
1:\S@@
2:Kernel@@\r
3:@@
打印行
[root@dy1 ~]# cat test.txt
00::11 22
33::44 55
66::77 88
//打印第二行
[root@dy1 ~]# awk 'NR==2{print $0}' test.txt
33::44 55
[root@dy1 ~]# awk 'NR==2{print $1}' test.txt
33::44
[root@dy1 ~]# awk -F"[: ]+" 'NR==2{print $1}' test.txt
33
//打印大于第1号,小于第3行的行的第一列,其实也就是第二行的第一列。
[root@dy1 ~]# awk -F"[: ]+" 'NR>1&&NR<3{print $1}' test.txt
33
//练习,打印用户的name和uid
[root@dy1 ~]# awk -F: '{print "name:" $1 "\t uid:" $3}' /etc/passwd | head -5
name:root uid:0
name:bin uid:1
name:daemon uid:2
name:adm uid:3
name:lp uid:4
//通过print不美观,通过printf会美观一些
[root@dy1 ~]# awk -F: '{printf "%-15s %-10s %-15s\n",$1,$2,$3}' /etc/passwd | head -5
root x 0
bin x 1
daemon x 2
adm x 3
lp x 4
awk -F: '{printf "%-15s %-10s %-15s\n","name:"$1,"this is:"$2,"uid:"$3}' /etc/passwd | head -5
name:root this is:x uid:0
name:bin this is:x uid:1
name:daemon this is:x uid:2
name:adm this is:x uid:3
name:lp this is:x uid:4
- %s 字符类型
- %d数值类型
- 占15个字符,-表示左对齐,尾部是右对齐
- printf 默认不会自动换行,需要加\n
2. GEGIN&END
[root@dy1 ~]# awk 'BEGIN {print "START"} {print "00"} END {print "END"}' /etc/hosts
START
00
00
END
仔细体会上面的例子,为什么00会显示两次呢?是因为/etc/hosts的文件有两行,文件有几行,这里面的00就会打印几次,主要还是因为awk的工作原理使然,其工作原理就是取一行处理一行,文件当中一共有两行内容,这里面的00就会打印两次。
那么BEGIN和END里面的内容只会打印一次呢?是因为BEGIN和END并不会参加到处理动作里面去,所以只打印一次,处理前打印一次,处理后打印一次。
3. 模式动作
正则表达式:
#匹配记录(整行)
[root@dy1 ~]# awk '/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@dy1 ~]# awk '$0 ~ /^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
匹配字段,匹配操作符
[root@dy1 ~]# awk '$1~/^root/' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@dy1 ~]# awk '$1 !~ /bash$/' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
比较表达式:
[root@dy1 ~]# awk -F: '$3==0' /etc/passwd
root:x:0:0:root:/root:/bin/bash
[root@dy1 ~]# awk -F: '$3<10' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@dy1 ~]# awk -F: '$7 == "/bin/bash"' /etc/passwd
root:x:0:0:root:/root:/bin/bash
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash
//磁盘使用率大于多少则打印可用的值
[root@dy1 ~]# df | awk '/\/$/'| awk '$3>100000 {print $4}'
44781576
条件表达式:
[root@dy1 ~]# awk -F: '$3>300 {print $0}' /etc/passwd
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
nginx:x:998:996:nginx user:/var/cache/nginx:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash
[root@dy1 ~]# awk -F: '{if($3>300) print $0}' /etc/passwd
polkitd:x:999:998:User for polkitd:/:/sbin/nologin
nginx:x:998:996:nginx user:/var/cache/nginx:/sbin/nologin
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
zhanghe:x:1000:1000::/home/zhanghe:/bin/bash
[root@dy1 ~]# awk -F: '{if($3>5555) {print $3} else {print $1}}' /etc/passwd | head -5
root
bin
daemon
adm
lp
运算:
[root@dy1 ~]# awk -F: '$3 * 10 > 50000' /etc/passwd
nfsnobody:x:65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
4. if
[root@dy1 ~]# df
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/mapper/centos-root 47023684 2242952 44780732 5% /
devtmpfs 1001880 0 1001880 0% /dev
tmpfs 1014044 0 1014044 0% /dev/shm
tmpfs 1014044 9776 1004268 1% /run
tmpfs 1014044 0 1014044 0% /sys/fs/cgroup
/dev/sda1 1038336 135368 902968 14% /boot
tmpfs 202812 0 202812 0% /run/user/0
//当用量超过9000时,就打印可用的空间
[root@dy1 ~]# df | awk '/\/run/{if ($3>9000) print "可用空间还有:"$4}'
可用空间还有:1004268
上述这个例子其实十分简单,取出有/run
的行,如果第三列大于9000,就打印第四列。