Error[8]: Undefined offset: 455, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始[+++]

分割

1 2 3 4 [+++] [+++] [+++] [+++][+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 456, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4 [+++] [+++] [+++] [+++][+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 457, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4  [+++] [+++] [+++][+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 458, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4   [+++] [+++][+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 459, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4    [+++][+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 460, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4    [+++] [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 461, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4     [+++] #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

Error[8]: Undefined offset: 462, File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 121
File: /www/wwwroot/outofmemory.cn/tmp/plugin_ss_superseo_model_superseo.php, Line: 473, decode(

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4      #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标 [+++] )
File: /www/wwwroot/outofmemory.cn/tmp/route_read.php, Line: 126, InsideLink()
File: /www/wwwroot/outofmemory.cn/tmp/index.inc.php, Line: 166, include(/www/wwwroot/outofmemory.cn/tmp/route_read.php)
File: /www/wwwroot/outofmemory.cn/index.php, Line: 30, include(/www/wwwroot/outofmemory.cn/tmp/index.inc.php)

linux 文本分析工具---awk命令_随笔_内存溢出

linux 文本分析工具---awk命令

linux 文本分析工具---awk命令,第1张

linux 文本分析工具---awk命令(7/1)

awk是一个强大的文本分析工具,相对于grep的查找,sed的编辑,awk在其对数据分析并生成报告时,显得尤为强大。


简单来说awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理。


awk有3个不同版本: awk、nawk和gawk,未作特别说明,一般指gawk,gawk 是 AWK 的 GNU 版本。


awk其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母。


实际上 AWK 的确拥有自己的语言: AWK 程序设计语言 , 三位创建者已将它正式定义为“样式扫描和处理语言”。


它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报 表,还有无数其他的功能。


awk '{pattern + action}' {filenames}

尽管 *** 作可能会很复杂,但语法总是这样,其中 pattern 表示 AWK 在数据中查找的内容,而 action 是在找到匹配内容时所执行的一系列命令。


花括号({})不需要在程序中始终出现,但它们用于根据特定的模式对一系列指令进行分组。


pattern就是要表示的正则表达式,用斜杠括起来。


awk语言的最基本功能是在文件或者字符串中基于指定规则浏览和抽取信息,awk抽取信息后,才能进行其他文本 *** 作。


完整的awk脚本通常用来格式化文本文件中的信息。


通常,awk是以文件的一行为处理单位的。


awk每接收文件的一行,然后执行相应的命令,来处理文本。


awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出
1.命令行方式
awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可选的。


input-file(s) 是待处理的文件。



在awk中,文件的每一行中,由域分隔符分开的每一项称为一个域。


通常,在不指名-F域分隔符的情况下,默认的域分隔符是空格。


2.shell脚本方式
将所有的awk命令插入一个文件,并使awk程序可执行,然后awk命令解释器作为脚本的首行,一遍通过键入脚本名称来调用。



相当于shell脚本首行的:#!/bin/sh
可以换成:#!/bin/awk 3.将所有的awk命令插入一个单独文件,然后调用:
awk -f awk-script-file input-file(s)
其中,-f选项加载awk-script-file中的awk脚本,input-file(s)跟上面的是一样的

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 & -f指定脚本文件 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   //匹配代码块 $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   IF语句 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           必须用在{}中,且比较内容用()扩起来 条件表达式 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    输出分隔符OFS 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           //取整   输出处理结果到文件 awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt awk '$6 ~ /WAIT/ || NR==1 {print NR,$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   IF语句 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}'   while语句 awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd   small awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd                                                                                                                    //ID大于100,A加1,否则B加1 awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳过,否则显示 awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd    awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd 另一种形式 awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd  awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd   数组 awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd  7 root 1       netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}' netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}' 9523                               1      应用1 应用2 awk -F: '{print NF}' 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: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔输出前5个字段,并打印行号   应用3 awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多个分隔符: #,输出每行多少字段 awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔输出多字段   应用4 awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三个分隔符,并输出每行字段数 awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔输出多字段   应用5 计算/home目录下,普通文件的大小,使用KB作为单位 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}' ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思   应用6 统计netstat -anp 状态为LISTEN和CONNECT的连接数量分别是多少 netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'   应用7 统计/home目录下不同用户的普通文件的总数是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'    mysql        199  root           374  统计/home目录下不同用户的普通文件的大小总size是多少? ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'   [root@Gin scripts] 输出成绩表 awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\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@localhost home]# cat test0  Marry   2143 78 84 77 Jack    2321 66 78 45 Tom     2122 48 77 71 Mike    2537 87 97 95 Bob     2415 40 57 62

awk 赋值运算符:a+5;等价于: a=a+5;其他同类 1 2 # awk 'BEGIN{a=5;a+=5;print a}'10 [root@Gin scripts] awk逻辑运算符: 1 2 # awk 'BEGIN{a=1;b=2;print (a>2&&b>1,a=1||b>1)}'0 1 [root@Gin scripts]

判断表达式 a>2&&b>1为真还是为假,后面的表达式同理

awk正则运算符: 1 2 # awk 'BEGIN{a="100testaa";if(a~/100/) {print "ok"}}'ok [root@Gin scripts] 1 2 # echo|awk 'BEGIN{a="100testaaa"}a~/test/{print "ok"}'ok [root@Gin scripts] 关系运算符:

如: > < 可以作为字符串比较,也可以用作数值比较,关键看 *** 作数如果是字符串就会转换为字符串比较。


两个都为数字 才转为数值比较。


字符串比较:按照ascii码顺序比较。


1 2 3 4 5 # awk 'BEGIN{a="11";if(a>=9){print "ok"}}' #无输出[root@Gin scripts] # awk 'BEGIN{a=11;if(a>=9){print "ok"}}' ok [root@Gin scripts] # awk 'BEGIN{a;if(a>=b){print "ok"}}'ok [root@Gin scripts] awk 算术运算符:

说明,所有用作算术运算符进行 *** 作, *** 作数自动转为数值,所有非数值都变为0。


1 2 3 4 # awk 'BEGIN{a="b";print a++,++a}'0 2 [root@Gin scripts] # awk 'BEGIN{a="20b4";print a++,++a}'20 22 [root@Gin scripts]

这里的a++ , ++a与javascript语言一样:a++是先赋值加++;++a是先++再赋值

三目运算符 ?: 1 2 3 4 # awk 'BEGIN{a="b";print a=="b"?"ok":"err"}'ok [root@Gin scripts] # awk 'BEGIN{a="b";print a=="c"?"ok":"err"}'err [root@Gin scripts] 常用 awk 内置变量

注:内置变量很多,参阅相关资料

字段分隔符 FS

FS="\t" 一个或多个 Tab 分隔

1 2 3 4 # cat tab.txtww   CC        IDD [root@Gin scripts] # awk 'BEGIN{FS="\t+"}{print ,,}' tab.txtww   CC        IDD [root@Gin scripts]

FS="[[:space:]+]" 一个或多个空白空格,默认的

1 2 3 4 5 6 # cat space.txtwe are    studing  awknow! [root@Gin scripts] # awk -F [[:space:]+] '{print ,,,,}' space.txtwe are   [root@Gin scripts] # awk -F [[:space:]+] '{print ,}' space.txtwe are [root@Gin scripts]

FS="[" ":]+" 以一个或多个空格或:分隔

1 2 3 4 # cat hello.txtroot:x:0:0:root: /root:/bin/bash[root@Gin scripts] # awk -F [" ":]+ '{print ,,}' hello.txtroot x 0 [root@Gin scripts]

字段数量 NF

1 2 3 4 5 # cat hello.txtroot:x:0:0:root: /root:/bin/bashbin:x:1:1:bin: /bin:/sbin/nologin:888[root@Gin scripts] # awk -F ":" 'NF==8{print bin:x:1:1:bin:}' hello.txt/bin :/sbin/nologin:888[root@Gin scripts]# ifconfig eth0|awk -F [" ":]+ 'NR==2{print }'  ## NR==2也就是取第2行

记录数量 NR

1 2 192.168.17.129[root@Gin scripts] # cat recode.txt

RS 记录分隔符变量
将 FS 设置成"\n"告诉 awk 每个字段都占据一行。


通过将 RS 设置成"",还会告诉 awk每个地址记录都由空白行分隔。


1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts] # cat hello.txt

OFS 输出字段分隔符

1 2 3 4 5 6 7 8 9 root:x:0:0:root:/root :/bin/bashbin:x:1:1:bin:/bin :/sbin/nologin:888[root@Gin scripts]# awk 'BEGIN{FS=":"}{print ","","}' hello.txt root,x,0bin,x,1 [root@Gin scripts] # awk 'BEGIN{FS=":";OFS="#"}{print ,,}' hello.txt root#x#0 bin#x#1 [root@Gin scripts]# cat recode.txt

ORS 输出记录分隔符

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 Jimmy the Weasel100 Pleasant Drive San Francisco,CA 123456 Big Tony 200 Incognito Ave.   Suburbia,WA 64890 [root@Gin scripts] # cat awk.txt #!/bin/awkBEGIN {          FS= "\n"        RS= ""        ORS= "\n\n"}{          print ","","}[root@Gin scripts] # awk -f awk.txt recode.txt Jimmy the Weasel,100 Pleasant Drive,San Francisco,CA 123456Big Tony,200 Incognito Ave.,Suburbia,WA 64890 [root@Gin scripts]   # awk '/root/{print root:x:0:0:root:}' passwd ##匹配所有包含root的行 awk 正则

正则应用

规则表达式

awk '/REG/{action} ' file,/REG/为正则表达式,可以将$0 中,满足条件的记录送入到:action 进行处理

1 2 3 4 5 6 7 8 9 /root: /bin/bashoperator:x:11:0:operator:/root: /sbin/nologin[root@Gin scripts]# awk -F: '~/root/{print root:x:0:0:root:}' passwd  ## 以分号作为分隔符,匹配第5个字段是root的行/root   :/bin/bash [root@Gin scripts]# ifconfig eth0|awk 'BEGIN{FS="[[:space:]:]+"} NR==2{print }'192.168.17.129[root@Gin scripts]   # awk -F: '=="root"{print root:x:0:0:root:}' passwd/root :

布尔表达式
awk '布尔表达式{action}' file 仅当对前面的布尔表达式求值为真时, awk 才执行代码块。


1 2 3 4 /bin/bash[root@Gin scripts] # awk -F: '(=="root")&&(=="root") {print root:x:0:0:root:}' passwd/root:/bin/bash {         if(=="foo"){ awk 的 if、循环和数组 条件语句

awk 提供了非常好的类似于 C 语言的 if 语句。


1 2 3 4 5 6 7 8 9 10 11 12 13                  if(== "foo"){                         print "uno"                }else {                        print  "one"                }         }elseif(=="bar"){                 print  "two"        }else {                print  "three"        }} /matchme/{ print } {   if

使用 if 语句还可以将代码:

1 ( /matchme/ !~ ) {     print

转换成:

1 2 3 4 5   } }{     count=1do {          print  "I get printed at least once no matter what"      循环结构

我们已经看到了 awk 的 while 循环结构,它等同于相应的 C 语言 while 循环。


 awk 还有"do...while"循环,它在代码块结尾处对条件求值,而不像标准 while 循环那样在开始处求值。


它类似于其它语言中的"repeat...until"循环。


以下是一个示例:
do...while 示例

1 2 3 4 5 while( count !=1 ) }for( initial assignment; comparison; increment ) {     code block} for ( x=1;x<=4;x++ ) {

与一般的 while 循环不同,由于在代码块之后对条件求值, "do...while"循环永远都至少执行一次。


换句话说,当第一次遇到普通 while 循环时,如果条件为假,将永远不执行该循环。


for 循环

awk 允许创建 for 循环,它就象 while 循环,也等同于 C 语言的 for 循环:

1 2 3      print  "iteration", x }

以下是一个简短示例:

1 2 3 iteration1 iteration2 iteration3iteration4while死循环 while

此段代码将打印:

1 2 3 4 (1) { print  "forever and ever..." } break 和 continue

此外,如同 C 语言一样, awk 提供了 break 和 continue 语句。


使用这些语句可以更好地控制 awk 的循环结构。


以下是迫切需要 break 语句的代码片断:

1 2 3 4 5 while 死循环 1 永远代表是真,这个  while #break 语句示例 x=1while (1) {   print  "iteration", x 循环将永远运行下去。


以下是一个只执行十次的循环:

1 2 3 4 5 6 7 8 9    if ( x==10 ) {     break  }  x++ }x=1while (1) {          if( x==4 ) {          x++         

这里, break 语句用于“逃出”最深层的循环。


 "break"使循环立即终止,并继续执行循环代码块后面的语句。



continue 语句补充了 break,其作用如下:

1 2 3 4 5 6 7 8 9 10 11 continue     }      print "iteration" , x     if( x>20 ) {         break    }     x++ } for( x=1;x<=21;x++ ) {     if ( x==4 ) {         continue

这段代码打印"iteration1"到"iteration21", "iteration4"除外。


如果迭代等于 4,则增加 x并调用 continue 语句,该语句立即使 awk 开始执行下一个循环迭代,而不执行代码块的其余部分。


如同 break 一样,

continue 语句适合各种 awk 迭代循环。


在 for 循环主体中使用时, continue 将使循环控制变量自动增加。


以下是一个等价循环:

1 2 3 4 5 6      }     print  "iteration" , x} {     cities[1]=”beijing”    cities[2]=”shanghai”     cities[“three”]=”guangzhou”

在while 循环中时,在调用 continue 之前没有必要增加 x,因为 for 循环会自动增加 x。


数组

AWK 中的数组都是关联数组,数字索引也会转变为字符串索引

1 2 3 4 5 6 7 8 9 10 11      for( c  incities) {         print cities[c]     }    print cities[1]      print cities[“1”]     print cities[“three”]} netstat-an| awk'/^tcp/{++s[$NF]}END{for(a in s)print a,s[a]}' ESTABLISHED 1LISTEN 20 awk

for…in 输出,因为数组是关联数组,默认是无序的。


所以通过 for…in 得到是无序的数组。


如果需要得到有序数组,需要通过下标获得。


数组的典型应用

用 awk 中查看服务器连接状态并汇总

1 2 3 '{a[]+=;++b[];total+=}END{ for(x  in a)print b[x],x,a[x]| "sort -rn -k1"

统计 web 日志访问流量,要求输出访问次数,请求页面或图片,每个请求的总大小,总访问流量的大小汇总

1 2 3 4 5 6 7 8 9 ;print "total size is :"total}' /app/log/access_logtotal size is :172230 21 /icons/poweredby.png 83076 14 / 70546/icons/apache_pb .gif 18608 a[]+= 表示以第 7 列为下标的数组( 列为 列的大小),把他们大小累加得到 每次访问的大小,后面的 for 循环有个取巧的地方, a 和 b 数组的下标相同,所以一 条 for语句足矣 awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'this is a  test !test ! 常用字符串函数

字符串函数的应用

替换

1 2 3 在 info 中查找满足正则表达式, /[0-9]+/ 用”!”替换,并且替换后的值,赋值给 info 未 给 info 值,默认是awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'ok #未找到,返回 0awk'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}' ok  #如果查找到数字则匹配成功返回 ok,否则失败,返回未找到

查找

1 2 awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}' s is a tes #从第 4 个 字符开始,截取 10 个长度字符串

匹配查找

1 2 awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}' 4

截取

1 2 test 1 this 2 is 3 a 1…n 开始

分割

1 2 3 4      #分割 info,动态创建数组 tA,awk for …in 循环,是一个无序的循环。


并不是从数组下标

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/587713.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-12
下一篇 2022-04-12

发表评论

登录后才能评论

评论列表(0条)

保存