awk是一种模式扫描和处理语言,是分析和处理数据时非常强大的工具。awk[options]'pattern{action}'file...awk的工作过程如下:逐行读取输入(标准输入或文件),对匹配模式pattern的行执行action。当模式省略时,表示匹配任意字符串;action省略时表示执行'{print}';它们不能同时被省略。每行输入对于awk来说都是一条记录,awk用$0来指代当前记录:[root@centos7~]#head-1/etc/passwd|awk'{print$0}'root:x:在0:0:root:/root:/bin/bash的例子中,命令head-1/etc/passwd作为awk的输入,awk省略了模式,动作为print$0,表示打印当前记录。对于每条记录,awk使用分隔符将其分成列,第一列用$1表示,第二列用$2表示...最后一列用$NF表示Option-F表示指定的分隔符如输出文件/etc/passwd的第一行第一列(用户名)和最后一列(登录shell):[root@centos7~]#head-1/etc/passwd|awk-F:'{print$1,$NF}'root/bin/bash当没有指定分隔符时,使用一个或多个空格(空白字符,由空格键或TAB键生成)作为分隔符。输出分隔符默认为空格。例如在输出命令ls-l*的结果中,文件大小和文件名:[root@centos7temp]#ls-l*|awk'{print$5,$NF}'13b.txt58c.txt12d.txt0e.txt0f.txt24test.sh[root@centos7temp]#你也可以过滤任何列:[root@centos7temp]#ls-l*|awk'$5>20&&$NF~/txt$/'-rw-r--r--1nobodynobody58November1616:34c.txt其中$5>20表示第五列大于20;&&表示逻辑与;$NF~/txt$/中,~表示Match,符号//里面是正则表达式。这里省略动作,整个awk语句的意思是打印文件大小大于20字节,文件名以txt结尾的行。awk用NR表示行号[root@centos7temp]#awk'/^root/||NR==2'/etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologin[root@centos7temp]#中例如,||表示逻辑或,语句表示:输出文件/etc/passwd中以root开头的行或第二行。在某些情况下使用awk过滤甚至比使用grep更灵活,比如在ifconfig的输出中获取网卡名称及其对应的mtu值[root@idc-v-71253~]#ifconfig|awk'/^\S/{print$1"\t"$NF}'ens32:1500ens33:1500lo:65536[root@idc-v-71253~]##这里的正则表达式是指不以空白字符开头的行,和输出格式为\t。上面提到的NR、NF等都是awk的内置变量,下面列出了一些常用的内置变量$0当前记录(这个变量存放的是整行的内容)$1~$n第n个当前记录的字段间隔由FS分隔FS输入字段分隔符默认为空白或TabNF。当前记录的字段数是多少列NR行号,从1开始,如果有多个文件,这个值也会不断累加。FNR输入文件行号RS输入记录分隔符,默认为换行符OFS输出字段分隔符,默认也是空格ORS输出记录分隔符,默认为换行符FILENAME当前输入文件名也可以使用awk中的自定义变量,比如把网卡的名字赋值给变量a,然后输出网卡的名字和它对应的RX字节的值(注意不同模式匹配和action的写法):[root@idc-v-71253~]#ifconfig|awk'/^\S/{a=$1}/RXp/{printa,$5}'ens32:999477100ens33:1663197120lo:0awk中有两种特殊模式:BEGIN和END;它们不会匹配输入的文本,BEGIN对应END的action部分组合成一个代码块,在任何输入开始之前执行;END对应的动作部分组合成一个代码块,在所有输入处理完成后执行。#注意类似C语言的赋值和打印函数用法[root@centos7temp]#ls-l*|awk'BEGIN{print"sizename\n--------"}$5>20{x+=$5;print$5,$NF}END{print"--------\ntotal",x}'sizename--------58c.txt24test.sh---------total82[root@centos7temp]#awk也支持数组,数组的索引都被当作字符串(即关联数组)处理。可以使用for循环遍历输出文件/etc/passwd中的数组元素各种登录shell及其总数#注意数组赋值和for循环遍历数组[root@centos7temp]#awk-F':''{a[$NF]++}END{for(iina)printi,a[i]}'/etc/passwd/bin/sync1/bin/bash2/sbin/nologin19/sbin/halt1/sbin/shutdown1[root@centos7temp]#当然还有if分支语句#注意花括号是如何定义actionblock的[root@centos7temp]#netstat-antp|awk'{if($6=="LISTEN"){x++}else{y++}}END{printx,y}'63[root@centos7temp]#模式可以用逗号分隔,表示从匹配第一个模式开始,直到匹配第二种模式[root@centos7~]#awk'/^root/,/^adm/'/etc/passwdroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologin也支持三元运算符pattern1?pattern2:pattern3,表示判断pattern1是否匹配,true匹配pattern2,false匹配pattern3,pattern也可以是类似C语言的表达式例如判断/etc/passwd文件中UID大于500的登录shell是否为/bin/bash,则输出整行,否则输出UID为0的行:#注意目录分隔符转义为了避免混淆[root@centos7~]#awk-F:'$3>500?/\/bin\/bash$/:$3==0{print$0}'/etc/passwdroot:x:0:0:root:/root:/bin/bashlearner:x:1000:1000::/home/learner:/bin/bash#三元运算符也可以嵌套,例子从略。选项-ffile表示从文件中读取awk指令#PrintFibonacci契约序列的前十项[root@centos7temp]#cattest.awkBEGIN{$1=1$2=1OFS=","for(i=3;i<=10;i++){$i=$(i-2)+$(i-1)}print}[root@centos7temp]#awk-ftest.awk1,1,2,3,5,8,13,21,34,55[root@centos7temp]#选项-F指定列分隔符#当使用多个字符作为分隔符时[root@centos7temp]#echo1.2,3:45|awk-F'[.,:]''{print$2,$NF}'25[root@centos7temp]##这里-F后面单引号里面的内容也是正则表达式选项-vvar=val设置变量#这里printf函数的用法类似于C语言中的同名函数[root@centos7~]#awk-vn=5'BEGIN{for(i=0;i
