咨询热线:4006-75-4006
售前:9:00-23:30 备案:9:00-18:00 技术:7*24h
该文章主要是以案例来讲解awk的使用方法,以及延伸到一些实际生产环境中使用(比如统计进程整体cpu或内存负载等)
首先,我们后边的操作以/tmp/file为例,内容如下:
[root@21yunwei tmp]# cat file ll 34523452345 80 97 70 kk 78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57 aa 78987897878 23 34 12
1,awk工作模式
awk 'BEGIN{ print "start"} pattern { commands } END{ print "end"}' file
awk是迭代处理,即一行行的处理。比如我们打印第1个字段结果的处理过程:先取第一行的第一个字段,然后再取第二行的第一个字段。。。一直到处理完整个数据流。:
[root@21yunwei tmp]# cat file |awk '{print $1}' ll kk hh jj aa
2,awk指定多个分隔符
awk默认是以空白为分隔符,如果有其他分隔符,我们需要使用-F’ ‘指定(类似cut -d’ ‘)。
[root@21yunwei /]# cat /etc/passwd | tail -2 |awk -F':' '{print $1}' user19 user20
也可以指定多个分隔符,通过正则[]来匹配,如果多个相同符号,我们可以'[ ]+’来将相同符号认为一个.比如我们修改文件file成如下内容:
[root@21yunwei tmp]# cat file ll:34523452345 80 97 70 kk:78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57 aa 78987897878 23 34 12
现在我们要取第二列:
[root@21yunwei tmp]# cat file |awk -F'[ :]' '{print $2}' 34523452345 78979797979 78979879797 23678236876 78987897878
如果我们前边变成两个冒号,就不可以这样写了,要写成:
[root@21yunwei tmp]# cat file |awk -F'[ :]+' '{print $2}'
没有+号,则两个冒号的无法显示,认为两个冒号之前认为是空白。其中多个空白也需要+号。
延伸实际应用,取服务器网卡IP:
[root@web9 tmp]# ifconfig eth0 eth0 Link encap:Ethernet HWaddr 52:54:00:8B:CA:F2 inet addr:192.168.1.9 Bcast:192.168.1.255 Mask:255.255.255.0 inet6 addr: fe80::5054:ff:fe8b:caf2/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
这个写法有很多,我们只举例awk,其他方式比如cut也可以获取。awk获取IP如下:
[root@21yunwei tmp]# ifconfig eth0 | grep "t a" |awk -F'[ :]+' '{print $4}' 192.168.1.9 [root@21yunwei tmp]# ifconfig eth0 | awk 'NR==2{print $0}' |awk -F'[ :]+' '{print $4}' 192.168.1.9
3,awk内置变量NF讲解
NF:每一行的字段数量,每一行的NF值可能不同也可能相同(number of filed)
比如我们查看file的最后一列和倒数第二列:
[root@21yunwei tmp]# cat file |awk '{print $NF,$(NF-1)}' 70 97 90 90 60 60 57 58 12 34
4,awk内置变量NR讲解
NR:数据流的行数,number of recoding
值如下:
[root@21yunwei tmp]# awk '{print NR}' file 1 2 3 4 5
举例我们分别打印第一行、打印2-4行:
[root@21yunwei tmp]# cat file |awk 'NR==1{print $0}' ll 34523452345 80 97 70 [root@21yunwei tmp]# cat file |awk 'NR==2,NR==4{print $0}' kk 78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57 [root@21yunwei tmp]# cat file |awk 'NR>1&&NR<5{print $0}' kk 78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57 [root@21yunwei tmp]# cat file |awk 'NR!=1&& NR!=5{print $0}' kk 78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57
取一行的第一列,取第三行的第二列:
[root@21yunwei tmp]# cat file |awk 'NR==1{print $1} NR==3{print $2}' ll 78979879797
扩展FNR,多个文件同时操作是分别记录文件行数。
5,awk的pattern介绍
pattern{action}pattern说白了就是一个判断,后边接action(动作),即'{}’ 花括号前边可以加一个判断,如果为真就执行后边的,如果是假,则不执行。具体可以参考上边行数判断取值。
比如’NR!=1&& NR!=5{print $0}’ ,其中NR!=1&& NR!=5就是pattern,{print $0}就是action
6,awk中BEGIN和END用法
BEGIN和END是一种特殊的模式,BEGIN是在pattern{action}首先执行,END是在pattern{action}执行后执行,即在文本处理前执行和文本执行后。执行效果如下:
[root@21yunwei tmp]# cat file |awk 'BEGIN{print "=====BEGIN======"}{print $0}END{print "=====END======"}' =====BEGIN====== ll 34523452345 80 97 70 kk 78979797979 90 90 90 hh 78979879797 60 60 60 jj 23678236876 59 58 57 aa 78987897878 23 34 12 =====END======
用途:可以用于变量赋值、最后取值、输出表头和表尾提示等。
7,awk计算方法
里边的计算类似C语言的计算方法,可以直接使用。
例1,取3 4 5行的和,取平均数,将取的平均数取整。注意:awk的计算支出小数,如果取整可以int。
[root@21yunwei tmp]# cat file |awk '{print $0,$3+$4+$5,($3+$4+$5)/3,int(($3+$4+$5)/3)}' ll 34523452345 80 97 70 247 82.3333 82 kk 78979797979 90 90 90 270 90 90 hh 78979879797 60 60 60 180 60 60 jj 23678236876 59 58 57 174 58 58 aa 78987897878 23 34 12 69 23 23 另一种写法: [root@21yunwei tmp]# cat file |awk '{sum=$3+$4+$5;print $0,sum,sum/3,int(sum/3)}' ll 34523452345 80 97 70 247 82.3333 82 kk 78979797979 90 90 90 270 90 90 hh 78979879797 60 60 60 180 60 60 jj 23678236876 59 58 57 174 58 58 aa 78987897878 23 34 12 69 23 23
例2,取第三个字段的总和并去平均值:
[root@21yunwei tmp]# cat file |awk '{total+=$3}END{print total,total/NR}' 312 62.4
延伸生产环境使用,统计httpd占用内存整体使用情况(也可以统计cpu,其他进程一样):
[root@21yunwei tmp]# ps aux | grep httpd |awk '{total+=$4};END{print total}' 20.8
统计php-fpm的cpu和内存使用:
[root@21yunwei mysqlbak]# ps aux |grep php-fpm|awk '{a+=$3;b+=$4}END{print "cpu:"a,"mem:"b}' cpu:3.1 mem:12.2
8,awk中if用法
用法: awk ‘{if(判断语句)print ….}’,建议将if判断加入花括号内部,这样{}外部就还可以写入其他的模式判断语句,当然也可以进行嵌套。
我们取第三列大于等于60的整行输出:
[root@21yunwei tmp]# cat file |awk '{if($3>=60)print $0}' ll 34523452345 80 97 70 kk 78979797979 90 90 90 hh 78979879797 60 60 60 以上结果等同于: [root@21yunwei tmp]# cat file |awk '$3>=60{print $0}' ll 34523452345 80 97 70 kk 78979797979 90 90 90 hh 78979879797 60 60 60
延伸:我们将/var/log/目录下大于25K的文件列出(当然find也是可以的):
[root@21yunwei log]# ll |awk '/^-/{if($5>25600){print $0}}' -rw------- 1 root root 328869 9月 2 02:30 cron -rw------- 1 root root 469313 8月 7 03:13 cron-20160807 -rw------- 1 root root 465889 8月 14 03:34 cron-20160814 -rw------- 1 root root 453704 8月 21 03:27 cron-20160821 -rw------- 1 root root 452841 8月 28 03:25 cron-20160828 -rw-r--r--. 1 root root 167384 10月 20 2015 dracut.log-20160101 -rw-r--r--. 1 root root 295504 9月 1 23:57 lastlog -rw------- 1 root root 411506 8月 31 16:50 maillog -rw------- 1 root root 887248 8月 7 03:10 maillog-20160807 -rw------- 1 root root 863595 8月 14 03:30 maillog-20160814 -rw------- 1 root root 810424 8月 21 03:25 maillog-20160821 -rw------- 1 root root 806775 8月 28 03:20 maillog-20160828 -rw------- 1 root root 40093034 9月 2 02:33 messages -rw------- 1 root root 56538021 8月 7 03:13 messages-20160807 -rw------- 1 root root 56686276 8月 14 03:34 messages-20160814 -rw------- 1 root root 56529992 8月 21 03:26 messages-20160821 -rw------- 1 root root 56520983 8月 28 03:25 messages-20160828 -rw------- 1 root root 190881 8月 6 23:05 secure-20160807 -rw------- 1 root root 62891 8月 12 20:56 secure-20160814 -rw-rw-r--. 1 root utmp 392448 9月 1 23:57 wtmp
默认是字节,我们需要换算一下。25K=1014*25
9,awk中变量介绍
awk可以自己定义新变量,类似C语言方法,定义的变量方便我们调用比如:
[root@21yunwei tmp]# cat file|awk '{total+=$NF}END{print total}' 289
比如我们之前统计httpd占用内存百分比,也使用到了变量:
[root@21yunwei tmp]# ps aux | grep httpd |awk '{total+=$4};END{print total}' 20.8
10,awk中for循环使用
awk的for循环,类似C语言中的for循环。举例如下:
[root@21yunwei tmp]# cat file |awk '{for(i=1;i<NF-2;i++){print $i}}' ll 34523452345 kk 78979797979 hh 78979879797 jj 23678236876 aa 78987897878
一行一行的处理,比如第一行,我们可以知道是i<3,即可i为1 2 ,则打印$1 $2两个字段。剩下每行也是打印$1 $2两个字段。
再弄一个取这个file?奇数列:
[root@21yunwei tmp]# cat file |awk '{for(i=1;i<=NF;i+=2){printf $i" "}print a}' ll 80 70 kk 90 90 hh 60 60 jj 59 57 aa 23 12
注意事项:步长+2,printf不换行输出加空格,可以让其整行输出;后边输出一个空变量做换行。取偶数列则起始值改成2.
11,awk正则表达式
awk '/^abc/{....}' 以abc开头 awk '!/^abc/{...}' 不是以abc开头 awk '/abc/{...}' 包含abc字符串 awk '!/abc/{...}' 不包含abc ~:匹配,可以和上边的结合使用。
举例如下:
[root@21yunwei tmp]# cat file |awk '/^kk/{print $0}' kk 78979797979 90 90 90 [root@21yunwei tmp]# cat file |awk '!/^kk/{print $0}' ll 34523452345 80 97 70 hh 78979879797 60 60 60 jj 23678236876 59 58 57 aa 78987897878 23 34 12 [root@21yunwei tmp]# cat file |awk '/6/{print $0}' hh 78979879797 60 60 60 jj 23678236876 59 58 57 [root@21yunwei tmp]# cat file |awk '!/6/{print $0}' ll 34523452345 80 97 70 kk 78979797979 90 90 90 aa 78987897878 23 34 12 [root@21yunwei tmp]# cat file |awk '!/6/&& $1~/kk/{print $0}' kk 78979797979 90 90 90 [root@21yunwei tmp]#
总结:awk是强大的工具,基本可以实现所有需要数据获取。有些时候grep、find、sed等可以相对实现功能,或其实现不了的功能awk也能实现。原则就是一个,满足功能需求的前提下什么方便使用什么。