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,就打印第四列。