linux:awk

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换行符

FSBEGIN时定义分隔符

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-fscript.awkfile

BEGIN{

FS=":"

}

{print$1}//效果与awk-F":"'{print$1}'相同,只是分隔符使用FS在代码自身中指定

awk'BEGIN{X=0}/^$/{X+=1}END{print"Ifind",X,"blanklines."}'test

Ifind4blanklines.

ls-l|awk'BEGIN{sum=0}!/^d/{sum+=$5}END{print"totalsizeis",sum}'//计算文件大小

totalsizeis17487

-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\tUid:"$3}'/etc/passwd//自定义输出

awk-F:'{printNF}'/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'{printNR,$0}'/etc/passwd//输出每行的行号

awk-F:'{printNR,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,2777...

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...else...

条件表达式

==!=>>=

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/{printint($2/1024)}'/proc/meminfo//取整

输出分隔符OFS

awk'$6~/FIN/||NR==1{printNR,$4,$5,$6}'OFS="\t"netstat.txt

awk'$6~/WAIT/||NR==1{printNR,$4,$5,$6}'OFS="\t"netstat.txt

//输出字段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";elseprint"small"}'/etc/passwd

small

small

small

large

small

small

awk-F:'BEGIN{A=0;B=0}{if($3>100){A++;print"large"}else{B++;print"small"}}END{printA,"\t",B}'/etc/passwd

//ID大于100,A加1,否则B加1

awk-F:'{if($3<100)next;elseprint}'/etc/passwd//小于100跳过,否则显示

awk-F:'BEGIN{i=1}{if(i<NF)printNR,NF,i++}'/etc/passwd

awk-F:'BEGIN{i=1}{if(i<NF){printNR,NF}i++}'/etc/passwd

另一种形式

awk-F:'{print($3>100?"yes":"no")}'/etc/passwd

awk-F:'{print($3>100?$3":\tyes":$3":\tno")}'/etc/passwd

while语句

awk-F:'BEGIN{i=1}{while(i<NF)printNF,$i,i++}'/etc/passwd

7root1

7x2

703

704

7root5

7/root6

数组

netstat-anp|awk'NR!=1{a[$6]++}END{for(iina)printi,"\t",a[i]}'

netstat-anp|awk'NR!=1{a[$6]++}END{for(iina)printf"%-20s%-10s%-5s\n",i,"\t",a[i]}'

95231

99291

LISTEN6

79031

3038/cupsd1

79131

108371

98331

应用1

awk-F:'{printNF}'helloworld.sh//输出文件每行有多少字段

awk-F:'{print$1,$2,$3,$4,$5}'helloworld.sh//输出前5个字段

awk-F:'{print$1,$2,$3,$4,$5}'OFS='\t'helloworld.sh//输出前5个字段并使用制表符分隔输出

awk-F:'{printNR,$1,$2,$3,$4,$5}'OFS='\t'helloworld.sh//制表符分隔输出前5个字段,并打印行号

应用2

awk-F'[:#]''{printNF}'helloworld.sh//指定多个分隔符:#,输出每行多少字段

awk-F'[:#]''{print$1,$2,$3,$4,$5,$6,$7}'OFS='\t'helloworld.sh//制表符分隔输出多字段

应用3

awk-F'[:#/]''{printNF}'helloworld.sh//指定三个分隔符,并输出每行字段数

awk-F'[:#/]''{print$1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}'helloworld.sh//制表符分隔输出多字段

应用4

计算/home目录下,普通文件的大小,使用KB作为单位

ls-l|awk'BEGIN{sum=0}!/^d/{sum+=$5}END{print"totalsizeis:",sum/1024,"KB"}'

ls-l|awk'BEGIN{sum=0}!/^d/{sum+=$5}END{print"totalsizeis:",int(sum/1024),"KB"}'//int是取整的意思

应用5

统计netstat-anp状态为LISTEN和CONNECT的连接数量分别是多少

netstat-anp|awk'$6~/LISTEN|CONNECTED/{sum[$6]++}END{for(iinsum)printf"%-10s%-6s%-3s\n",i,"",sum[i]}'

应用6

统计/home目录下不同用户的普通文件的总数是多少?

ls-l|awk'NR!=1&&!/^d/{sum[$3]++}END{for(iinsum)printf"%-6s%-5s%-3s\n",i,"",sum[i]}'

mysql199

root374

统计/home目录下不同用户的普通文件的大小总size是多少?

ls-l|awk'NR!=1&&!/^d/{sum[$3]+=$5}END{for(iinsum)printf"%-6s%-5s%-3s%-2s\n",i,"",sum[i]/1024/1024,"MB"}'

应用7

输出成绩表

awk'BEGIN{math=0;eng=0;com=0;printf"Lineno.NameNo.MathEnglishComputerTotal\n";printf"------------------------------------------------------------\n"}{math+=$3;eng+=$4;com+=$5;printf"%-8s%-7s%-7s%-7s%-9s%-10s%-7s\n",NR,$1,$2,$3,$4,$5,$3+$4+$5}END{printf"------------------------------------------------------------\n";printf"%-24s%-7s%-9s%-20s\n","Total:",math,eng,com;printf"%-24s%-7s%-9s%-20s\n","Avg:",math/NR,eng/NR,com/NR}'test0

[root@localhosthome]#cattest0

Marry2143788477

Jack2321667845

Tom2122487771

Mike2537879795

Bob2415405762