Linux常⽤指令之AWK(过滤搜索)
什么是awk?
与其它⼤多数UNIX命令不同的是,从名字上看,我们不可能知道awk的功能:它既不是具有独⽴意义的英⽂单词,也不是⼏个相关单词的缩写。事实上,awk是三个⼈名的缩写,他们是:Aho、(Peter)Weinberg和(Brain)Kernighan。正是这三个⼈创造了awk---⼀个优秀的样式扫描与处理⼯具。
AWK的功能是什么?与sed和grep很相似,awk是⼀种样式扫描与处理⼯具。但其功能却⼤⼤强于sed和grep。awk提供了极其强⼤的功能:它⼏乎可以完成grep和sed所能完成的全部⼯作,同时,它还可以可以进⾏样式装⼊、流控制、数学运算符、进程控制语句甚⾄于内置的变量和函数。它具备了⼀个完整的语⾔所应具有的⼏乎所有精美特性。实际上,awk的确拥有⾃⼰的语⾔:awk程序设计语⾔,awk 的三位创建者已将它正式定义为:样式扫描和处理语⾔。
为什么使⽤awk?
使⽤awk的第⼀个理由是基于⽂本的样式扫描和处理是我们经常做的⼯作,awk所做的⼯作有些象数据库,但与数据库不同的是,它处理的是⽂本⽂件,这些⽂件没有专门的存储格式,普通的⼈们就能编辑、阅读、理解和处理它们。⽽数据库⽂件往往具有特殊的存储格式,这使得它们必须⽤数据库处理程
序来处理它们。既然这种类似于数据库的处理⼯作我们经常会遇到,我们就应当到处理它们的简便易⾏的⽅法,UNIX有很多这⽅⾯的⼯具,例如sed 、grep、sort以及find等等,awk是其中⼗分优秀的⼀种。
使⽤awk的第⼆个理由是awk是⼀个简单的⼯具,当然这是相对于其强⼤的功能来说的。相对其他程序语⾔来说,awk完成同样的功能要⽅便和简捷得多。这⾸先是因为awk提供了适应多种需要的解决⽅案:从解决简单问题的awk命令⾏到复杂⽽精巧的awk程序设计语⾔,这样做的好处是,你可以不必⽤复杂的⽅法去解决本来很简单的问题。例如,你可以⽤⼀个命令⾏解决简单的问题,⽽C不⾏,即使⼀个再简单的程序,C语⾔也必须经过编写、编译的全过程。其次,awk本⾝是解释执⾏的,这就使得awk程序不必经过编译的过程,同时,这也使得它与shell程序能够很好的契合。最后,awk本⾝较C语⾔简单,是⼀种功能强⼤且不需要⼤量时间学习就能掌握其技巧的开发⼯具。
使⽤awk的第三个理由是awk是⼀个容易获得的⼯具。与C和C++语⾔不同,awk只有⼀个⽂件(/bin/awk),⽽且⼏乎每个版本的UNIX都提供各⾃版本的awk,你完全不必费⼼去想如何获得awk。
基于以上理由,再加上awk强⼤的功能,我们有理由说,如果你要处理与⽂本样式扫描相关的⼯作,awk应该是你的第⼀选择。在这⾥有⼀个可遵循的⼀般原则:如果你⽤普通的shell有困难的话,试试awk。如果awk仍不能解决问题,则便⽤其他如python等语⾔。
awk是⾏处理器: 相⽐较屏幕处理的优点,在处理庞⼤⽂件时不会出现内存溢出或是处理缓慢的问题,通常⽤来格式化⽂本信息。
⽰例如下:
awk处理过程: 依次对每⼀⾏进⾏处理,然后输出
awk命令形式:
awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file
[-F|-f|-v] ⼤参数,-F指定分隔符,-f调⽤脚本,-v定义变量 var=value
' ' 引⽤代码块
BEGIN 初始化代码块,在对每⼀⾏进⾏处理之前,初始化代码,主要是引⽤全局变量,设置FS分隔符
// 匹配代码块,可以是字符串或正则表达式
{} 命令代码块,包含⼀条或多条命令
; 多条命令使⽤分号分隔
END 结尾代码块,在对每⼀⾏进⾏处理之后再执⾏的代码块,主要是进⾏最终计算或输出结尾摘要信
特殊要点:
$0 表⽰整个当前⾏
$1 每⾏第⼀个字段
NF 字段数量变量
NR 每⾏的记录号,多⽂件记录递增
FNR 与NR类似,不过多⽂件记录不递增,每个⽂件都从1开始
\t 制表符
\n 换⾏符
FS BEGIN时定义分隔符
RS 输⼊的记录分隔符, 默认为换⾏符(即⽂本是按⼀⾏⼀⾏输⼊)
~ 匹配,与==相⽐不是精确⽐较
!~ 不匹配,不精确⽐较
== 等于,必须全部相等,精确⽐较
!= 不等于,精确⽐较
&& 逻辑与
|| 逻辑或
+ 匹配时表⽰1个或1个以上
/[0-9][0-9]+/ 两个或两个以上数字
/[0-9][0-9]*/ ⼀个或⼀个以上数字
FILENAME ⽂件名
OFS 输出字段分隔符, 默认也是空格,可以改为制表符等
ORS 输出的记录分隔符,默认为换⾏符,即处理结果也是⼀⾏⼀⾏输出到屏幕
-F'[:#/]' 定义三个分隔符
print & $0
print 是awk打印指定内容的主要命令
awk '{print}' /etc/passwd == awk '{print $0}' /etc/passwd
awk '{print " "}' /etc/passwd //不输出passwd的内容,⽽是输出相同个数的空⾏,进⼀步解释了awk是⼀⾏⼀⾏处理⽂本
awk '{print "a"}' /etc/passwd //输出相同个数的a⾏,⼀⾏只有⼀个a字母
awk -F":" '{print $1}' /etc/passwd
awk -F: '{print $1; print $2}' /etc/passwd //将每⼀⾏的前⼆个字段,分⾏输出,进⼀步理解⼀⾏⼀⾏处理⽂本
awk -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd //输出字段1,3,6,以制表符作为分隔符
-f指定脚本⽂件
awk -f script.awk file
BEGIN{
FS=":"
}
{print $1} //效果与awk -F":" '{print $1}'相同,只是分隔符使⽤FS在代码⾃⾝中指定
awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test
I find 4 blank lines.
ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}' //计算⽂件⼤⼩
total size is 17487
-
F指定分隔符
$1 指指定分隔符后,第⼀个字段,$3第三个字段, \t是制表符
⼀个或多个连续的空格或制表符看做⼀个定界符,即多个空格看做⼀个空格
awk -F":" '{print $1}' /etc/passwd
awk -F":" '{print $1 $3}' /etc/passwd //$1与$3相连输出,不分隔
awk -F":" '{print $1,$3}' /etc/passwd //多了⼀个逗号,$1与$3使⽤空格分隔
awk -F":" '{print $1 " " $3}' /etc/passwd //$1与$3之间⼿动添加空格分隔
awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd //⾃定义输出
awk -F: '{print NF}' /etc/passwd //显⽰每⾏有多少字段
awk -F: '{print $NF}' /etc/passwd //将每⾏第NF个字段的值打印出来
awk -F: 'NF==4 {print }' /etc/passwd //显⽰只有4个字段的⾏
awk -F: 'NF>2{print $0}' /etc/passwd //显⽰每⾏字段数量⼤于2的⾏
awk '{print NR,$0}' /etc/passwd //输出每⾏的⾏号
awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd //依次打印⾏号,字段数,最后字段值,制表符,每⾏内容awk -F: 'NR==5{print}' /etc/passwd //显⽰第5⾏
awk -F: 'NR==5 || NR==6{print}' /etc/passwd //显⽰第5⾏和第6⾏
route -n|awk 'NR!=1{print}' //不显⽰第⼀⾏
//匹配代码块
//纯字符匹配 !//纯字符不匹配 ~//字段值匹配 !~//字段值不匹配 ~/a1|a2/字段值匹配a1或a2
awk '/mysql/' /etc/passwd
awk '/mysql/{print }' /etc/passwd
awk '/mysql/{print $0}' /etc/passwd //三条指令结果⼀样
awk '!/mysql/{print $0}' /etc/passwd //输出不匹配mysql的⾏
awk '/mysql|mail/{print}' /etc/passwd
awk '!/mysql|mail/{print}' /etc/passwd
awk -F: '/mail/,/mysql/{print}' /etc/passwd //区间匹配
awk '/[2][7][7]*/{print $0}' /etc/passwd //匹配包含27为数字开头的⾏,如27,277, awk -F: '$1~/mail/{print $1}' /etc/passwd //$1匹配指定内容才显⽰
awk -F: '{if($1~/mail/) print $1}' /etc/passwd //与上⾯相同
awk -F: '$1!~/mail/{print $1}' /etc/passwd //不匹配
awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwd
IF语句
必须⽤在{}中,且⽐较内容⽤()扩起来
awk -F: '{if($1~/mail/) print $1}' /etc/passwd //简写
awk -F: '{if($1~/mail/) {print $1}}' /etc/passwd //全写
awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd //if...
条件表达式
linux重定向== != > >=
awk -F":" '$1=="mysql"{print $3}' /etc/passwd
awk -F":" '{if($1=="mysql") print $3}' /etc/passwd //与上⾯相同
awk -F":" '$1!="mysql"{print $3}' /etc/passwd //不等于
awk -F":" '$3>1000{print $3}' /etc/passwd //⼤于
awk -F":" '$3>=100{print $3}' /etc/passwd //⼤于等于
awk -F":" '$3<1{print $3}' /etc/passwd //⼩于
awk -F":" '$3<=1{print $3}' /etc/passwd //⼩于等于
逻辑运算符
&& ||
awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd //逻辑与,$1匹配mail,并且$3>8
awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwd
awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd //逻辑或
awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd
数值运算
awk -F: '$3 > 100' /etc/passwd
awk -F: '$3 > 100 || $3 < 5' /etc/passwd
awk -F: '$3+$4 > 200' /etc/passwd
awk -F: '/mysql|mail/{print $3+10}' /etc/passwd //第三个字段加10打印
awk -F: '/mysql/{print $3-$4}' /etc/passwd //减法
awk -F: '/mysql/{print $3*$4}' /etc/passwd //求乘积
awk '/MemFree/{print $2/1024}' /proc/meminfo //除法
awk '/MemFree/{print int($2/1024)}' /proc/meminfo //取整
输出分隔符OFS
awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t"
awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t"
//输出字段6匹配WAIT的⾏,其中输出每⾏⾏号,字段4,5,6,并使⽤制表符分割字段
输出处理结果到⽂件
①在命令代码块中直接输出 route -n|awk 'NR!=1{print > "./fs"}'
②使⽤重定向进⾏输出 route -n|awk 'NR!=1{print}' > ./fs
格式化输出
netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}'
printf表⽰格式输出
%格式化输出分隔符
-8长度为8个字符
s表⽰字符串类型
打印每⾏前三个字段,指定第⼀个字段输出字符串类型(长度为8),第⼆个字段输出字符串类型(长度为8),第三个字段输出字符串类型(长度为10)
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'
netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'
IF语句
awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd
small
small
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论