AWK尹会生--2010.9.6注:本文档中的代码和图片均来自《sed与awk(第二版)》1一编写awk脚本HELLO,WORLD$echo'thislineofdataisignored'test$awk'{printHello,world}'testHello,worldtest文件只包含一行,因此,print操作只执行一次。$cattest2Hello,world$awk'{print}'test2Hello,worldprint语句没有参数,只简单输出每个输入行。$awk‘BEGIN{print“hello,World”}’Hello,World2BEGIN模式不需要等待输入,它在第一个输入行读入之前执行。awk程序设计模型awk程序由所谓的主输入(maininput)循环组成。一个循环称作一个例程。awk允许你编写两个特殊的例程,他们在任何输入被读取前和所有输入都被读取后执行。他们是与BEGIN和END规则相关的过程。BEGIN和END过程是可选的。模式匹配src1.awk#testforinteger,stringoremptyline./[0-9]+/{printThatisaninteger}/[A-Za-z]+/{printThisisastring}/^$/{printThisisablankline.}3一个特殊的例子:$awk-fawkscr4TThatisanintegerThisisastring一行可以匹配一条或多条规则程序脚本的注释#以#号开始的一行记录和字段awk假设它的输入是有结构的,而不是一串无规则的字符。默认它将每个输入行作为一条记录,而将由空格或制表符分隔的单词作为字段。连续的多个空格和/或制表符被作为一个分隔符。JohnRobinson666-555-1111字段的引用和分离awk允许使用字段操作符$来指定字段。$后面可以跟着一个数字或者一个变量。$1表示第一个字段,$2表示第二个字段,$0表示整个输入记录。$awk'{print$2,$1,$3}'namesRobinsonJohn666-555-11114可以使用计算值为整数的表达式来表示一个字段$echoabcd|awk'BEGIN{one=1;two=2}{print$(one+two)}'c可以使用-F来改变字段分隔符$awk-F\t'{print$2}'names666-555-1111$awk-F\t+'{print$2}'names$awk-F[‘:\t]'{print$2}'names任何3个字符之一都可以被解释为字段分隔符也可以在脚本中指定域分隔符,通过系统变量FS来改变BEGIN{FS=,}#comma-delimitedfields{print$1-$2}使用匹配规则/MA/{print$1,$6}5为了避免假警报,可以使用更精确的匹配$5~/MA/{print$1,$6}还可以使用!来反转这个规则的意义$5!~/MA/{print$1,$6}表达式常量分成两种:字符串型和数字型字符串型在表达式中必须用引号括起来字符串中可以使用转义序列,常用的转义序列有:\n换行\t水平制表符\r回车变量x=1x是变量的名字=是一个赋值操作符1是一个数字常量注意:变量区分大小写,所以x和X(大写)表示不同的变量变量名只能由数字字母下划线组成,而且不能以数字开头变量使用不区分类型,使用前不必初始化z=Hello6z=HelloWorldz=$1以上几种都是合法的常用算数操作符OperatorDescription+Addition-Subtraction*Multiplication/Division%Modulox=1给x赋值y=x+1计算x的值,使它加1,并将结果赋给变量y。printy打印y的值。我们可以将这3个语句减少为两个:x=1printx+17常用赋值操作符OperatorDescription++Add1tovariable.--Subtract1fromvariable.+=Assignresultofaddition.-=Assignresultofsubtraction.*=Assignresultofmultiplication./=Assignresultofdivision.%=Assignresultofmodulo.^=Assignresultofexponentiation.计算文件中空行的数目#Countblanklines./^$/{printx+=1}x=x+1x+=1++xx++这几种有什么区别?#Countblanklines./^$/{++x}END{printx8}计算学生的平均成绩mona707785837089john859278948891andrea899085949095jasper848880928482dunce648060606162ellis909889969692$awk-fsrc2.awkgradesjohn87.4andrea86jasper85.6src2.awk#averagefivegrades{total=$2+$3+$4+$5+$6avg=total/5print$1,avg}9也可以使用print$1,total/5系统变量FS定义字段分隔符,默认为一个空格OFS输出的字段分隔符,默认为一个空格RS记录分隔符,默认为一个换行符ORS输出的记录分隔符,默认为一个换行符NR行数FNR行数,多文件操作时会重新排序NF输出当前输入记录的编号(字段的个数)FILENAME文件名例如:$awk–F:‘OFS=”aaa”,ORS=”bbb”{printNR,FNR,NF,FILENAME}’/etc/passwda.txt$printNR“.”,$1,avg1.john87.42.andrea863.jasper85.610处理多行记录JohnRobinsonKorenInc.978CommonwealthAve.BostonMA01760696-0987#block.awk-printfirstandlastfields#$1=name;$NF=phonenumberBEGIN{FS=\n;RS=}{print$1,$NF}$awk-fblock.awkphones.blockJohnRobinson696-0987PhyllisChapman879-0900JeffreyWillis914-636-0000AliceGold(707)724-0000BillGold1-707-724-0000关系操作符和布尔操作符关系操作符11OperatorDescriptionLessthanGreaterthan=Lessthanorequalto=Greaterthanorequalto==Equalto!=Notequalto~Matches!~DoesnotmatchNF==5NF(每个输入记录的字段数)的值和5相比较,如果结果为真,那么就进行相应的处理,否则不进行处理。$5~/MA/{print$1“,”$6}注意:关系操作符==和赋值操作符=是不同的布尔操作符OperatorDescription||LogicalOR&&LogicalAND!LogicalNOTNF==6&&NR1字段的数量必须等于6并且记录的编号必须大于1。NR1&&NF=2||$1~/\t/(NR1&&NF=2)||$1~/\t/!(NR1&&NF3)获取文件的信息12$ls-l|awk-fsrc3.awkBEGIN{printBYTES,\t,FILE}{sum+=$5++filenumprint$5,\t,$8}END{printTotal:,sum,bytes(filenumfiles)}格式化打印printf(format-expression[,arguments])CharacterDescriptioncASCII字符d十进制整数f浮点格式s字符串x无符号十六进制13常用举例:语法%-width.precisionformat-specifierprintf(%d\t%s\n,$5,$8)printf(|%10s|\n,hello)右对齐printf(|%-10s|\n,hello)左对齐printf(%*.*f\n,5,3,myvar)宽度5精度3打印myvar向脚本传递参数awk'script'var=valueinputfile$var=root$awk–F:-va=$var‘$1==a{print}’/etc/passwd二条件、循环和数组条件语句if(expression)action1[elseaction2]14例如:if(x)printx如果x是零,则print语句将不执行。如果x是一个非零值,将打印x的值。if(x==y)printxif(x~/[yY](es)?/)printx如果操作是由多个语句组成,要用一个大括号将操作括起来if(expression){statement1statement2}其他的例子:if(avg=65)grade=Passelsegrade=Failif(avg=90)grade=Aelseif(avg=80)grade=Belseif(avg=70)grade=Celseif(avg=60)grade=D15elsegrade=F这种能够连续条件只有当一个条件表达式计算结果为真时才停止求值,这时将跳过其他的条件。如果没有一个条件表达式的计算结果为真,将执行最后的else部分。条件操作符expr?action1:action2例如:grade=(avg=60)?Pass:Fail循环while循环while循环语法:while(condition)action例如:i=1while(i=4){print$i++i}16do循环doactionwhile(condition)例如:BEGIN{do{++xprintx}while(x=4)}for循环for(set_counter;test_counter;increment_counter)action例如:从第一个字段到最后一个字段for(i=1;i=NF;i++)print$i从最后一个字段到第一个字段for(i=NF;i=1;i--)17print$i用for实现total=0for(i=2;i=NF;++i)#total=$2+$3+$4+$5+$6#avg=total/5total+=$iavg=total/(NF-1)求阶乘5!=5*4*3*2*1fact=numberfor(x=number-1;x1;x--)fact*=x完整脚本factorial影响流控制的其他语句影响控制流break退出循环continue终止当前的循环,并从循环的顶部开始一个新的循环18影响主输入循环next读入下一行,并返回脚本的顶部exit使主输入循环退出并将控制转移到END数组array[subscript]=value在awk中不必指明数组的大小,只需要为数组制定标示符。可以用数字作为数组的下标,也可以用字符来做数组的下标。flavor[1]=tulipstudent_avg[NR]=avg关联数组在awk中,所有的数组都是关联数组。关联数组的独特之处在于它的下标可以是一个字符串或一个数值。有一个特殊的循环语法可以访问关联数组的所有元素for(variableinarray)dosomethingwitharray[variable]例如:19for(iteminacro)printitem,acro[item]一个计算学生成绩的例子:mona707785837089john859278948891andrea899085949095jasper848880928482dunce648060606162ellis909889969692#grades.awk--averagestudentgradesandde