awk基础

awk语言

最基本功能是在文件或字符串中基于指定规则浏览和抽取信息。

awk抽取信息后,才能进行其他文本操作。完整的awk脚本通常用来格式化文本文件中的信息。

=================================================================================

有三种方法调用awk

第一种命令行方式

awk[-Ffield-separator]'commands'input-file(s)

这里的commmands是真正的awk命令

第二种方法是将所有awk命令插入一个文件,并使awk程序可执行chmodu+xscriptfile,然后用awk命令解释器作为脚本的首行,以便通过键入脚本名称来调用它。

第三种方式是将所有的awk命令插入一个单独文件,然后调用:

awk-fawk-script-fileinput-file(s)

-f选项指明在文件awk_script_file中的awk脚本,input_file(s)是使用awk进行浏览的文件名。

=================================================================================

awk脚本整体结构

任何awk语句都由模式和动作组成。在一个awk脚本中可能有许多语句。

模式部分决定动作语句何时触发及触发事件。

如果省略模式部分,动作将时刻保持执行状态。模式可以是任何条件语句或复合语句或正则表达式。模式包括两个特殊字段BEGIN和END。使用BEGIN语句设置计数和打印头。BEGIN语句使用在任何文本浏览动作之前,之后文本浏览动作依据输入文件开始执行。END语句用来在awk完成文本浏览动作后打印输出文本总数和结尾状态标志。如果不特别指明模式,awk总是匹配或打印行数。

动作即对数据进行的操作。

实际动作在大括号{}内指明。动作大多数用来打印,但是还有些更长的代码诸如if和循环looping语句及循环退出结构。如果不指明采取动作,awk将打印出所有浏览出来的记录。

awk'BEGIN{print"Name\n------"}{print$1}END{print"end-of-report"}'testfile

文本操作前执行文本操作文本操作后执行

awk的域的概念

awk执行时,其浏览域标记为$1,$2...$n。这种方法称为域标识。使用这些域标识将更容易对域进行进一步处理。使用$1,$3表示参照第1和第3域,注意这里用逗号做域分隔。如果希望打印一个有5个域的记录的所有域,不必指明$1,$2,$3,$4,$5,可使用$0,意即所有域。awk浏览时,到达一新行,即假定到达包含域的记录末尾,然后执行新记录下一行的读动作,并重新设置域分隔。

awk'{print$0}'testfile

打印整个文件

awk'{print$1,$4}'testfile

打印文件中的第一列和第四列

注意事项:

确保整个awk命令用单引号括起来。

确保命令内所有引号成对出现。

确保用花括号括起动作语句,用圆括号括起条件语句。

=====================================================================================

条件操作符:

<小于

>=大于等于

<=小于等于

==等于(字符串用双引号包含)

!=不等于

!~不匹配正则表达式(正则表达式用//包含)注意这与grep不同,grep用单引号包含正则表达式

~匹配正则表达式

awk'{if($4~/Brown/)print$0}'testfile

awk'{if($3~/48/)print$0}'testfile等价于awk'$3=="48"{print$0}'testfile注意:if属于动作,而后者不算在动作里,故不用扩在{}里面

awk'$0~/(Yellow|Brown)/'testfile注意$0代表整行,默认的动作就是打印

awk'{if($4=="Yellow"||$4~/Brown/)print$0}'testfile注意:正则表达式里面用|而条件判断里面用||&&!

awk'/[Gg]reen/'testfile注意:$0为默认值,打印为默认动作

=====================================================================================

awk内置变量

ARGC命令行参数个数

ARGV命令行参数排列

ENVIRON支持队列中系统环境变量的使用

FILENAMEawk浏览的文件名

FNR浏览文件的记录数

FS设置输入域分隔符,等价于命令行-F选项fieldseparator

RS控制记录分隔符recordsepatator

OFS输出域分隔符

ORS输出记录分隔符

注意:NF和NR只是一个索引值,就是一个数字,也就是当前光标对应的位置的记录,当对他们取$NF,$NR时,显示的是他们对应的位置的值

NR只增不减,而NF是循环的增减,当达到每行的最大域数的时候时就跳到下一行从新清零。所以常用$NF保留最后一个域值

NF浏览记录的域个数numberoffield也就是行中域的个数

NR已读的记录数numberofrecord也就是行号

NF变量显示每一条读记录中有多少个域

awk'{if(NR>0&&$4~/Brown/)printNF,NR,$0}'testfile

另一个应用$NF保存最后一个域的值

echo"/usr/local/etc/rc.sybase"|awk-F/'{print$NF}'

=====================================================================================

在awk中使用操作符

基本表达式可以划分为数字型、字符串型、变量型、域及数组元素。

=+=*=/=%=^=赋值操作符

?条件表达操作符

||&&!并、与、非

~!~匹配操作符,包括匹配和不匹配

<<===!=>>关系操作符

+-*/%^算术操作符

++--前缀和后缀

设定有意义的域值变量

$1..没有意义,应该设定有意义的变量

awk'{name=$1;belts=$4;if(belts~/Yellow/)printname"isbelt"belts}'testfile

域值比较

有两种方式测试一数值域是否小于另一数值域。

1)在BEGIN中给变量名赋值。

2)在关系操作中使用实际数值。

通常在BEGIN部分赋值是很有益的,可以在awk表达式进行改动时减少很多麻烦。

awk'BEGIN{BASELINE="27"}{if($6<BASELINE)print$0}'grade.txt

注意:BEGIN部分只能使用常量,而不能使用参数如$n,因为此时还没有进行正文处理,会出现错

修改域

当在awk中修改任何域时,重要的一点是要记住实际输入文件是不可修改的,修改的只是保存在缓存里的awk复本。

awk会在变量NR或NF变量中反映出修改痕迹。

awk'{name=$1;if(name=="J.Troll")(name="J.L.Troll")(name="J.K.Troll");print$1}'testfile

逻辑操作表达式单独使用时要用()括起来,上面的if的范围一直到后面的;为止

只显示修改的部分

awk'{name=$1;if(name=="J.Troll"){name="J.L.Troll";print$1}}'testfile

用{}括起来则表示一个语句块,这样就只显示修改过的部分了

创建新的域

awk'BEGIN{print"Name\tDifference"}{if($6<$7){$8=$7-$6;print$1,$8}}'testfile

统计列值

awk'(tot+=$6);END{print"Clubstudenttotalpoints:"tot}'

上述将打印整个文件的内容

awk'{(tot+=$6)};END{print"Clubstudenttotalpoints:"tot}'

用{}括起来的话,动作就不是默认的print了,

应用于统计文件的大小:

ls-l|awk'/^[^d]/{print$9"\t"$5}{tot+=$5}END{print"totalKB:"tot}'

其中$9是文件名,$5是文件的大小,对应于ls命令的输出

======================================================================================

内置的字符串函数

gsub(r,s)在整个$0中用s替代r

gsub(r,s,t)在整个t中用s替代r

index(s,t)返回s中字符串t的第一位置

length(s)返回s长度

match(s,r)测试s是否包含匹配r的字符串

split(s,a,fs)在fs上将s分成序列a

sprint(fmt,exp)返回经fmt格式化后的exp

sub(r,s)用$0中最左边最长的子串代替s

substr(s,p)返回字符串s中从p开始的后缀部分

substr(s,p,n)返回字符串s中从p开始长度为n的后缀部分

注意:这些函数都放在BEGIN和END部分使用

awk标准格式化输出函数printf

类似于C语言的

======================================================================================

参数传递

管道传入字符串

echo"Helloworld!"|awk'{print$1}'

作为命令参数传递

awk'{if($5<AGE)print$0}'AGE=10grade.txt

=======================================================================================

数组的使用

参看:http://bbs.chinaunix.net/viewthread.php?tid=448687&extra=&page=3

#!/bin/awk-f

#name:belts.awk

BEGIN{

FS="#"

belt["Yellow"]

belt["Orange"]

belt["Red"]

student["Junior"]

student["Senior"]

}

##初始化完成后,BEGIN部分结束。记住BEGIN部分并没有文件处理操作。

#现在可以处理文件了。

{

for(colourinbelt)

{

if($1==colour)

belt[colour]++

}

}

{

for(senior_or_juniorinstudent)

{

if($2==senior_or_junior)

student[senior_or_junior]++

}

}

#END部分打印浏览结果,对每一个数组使用循环语句并打印它。

END{

for(colourinbelt)print"Theclubhas",belt[colour],colour,"Belts"

for(senior_or_juniorinstudent)print"Theclubhas",student[senior_or_junior],senior_or_junior,"student"

}

======================================================================================

注意在使用awk“脚本”时(而不是命令时,上述讲的都是命令行的),记住设置FS变量是在BEGIN部分。如果不这样做,awk将会发生混淆,不知道域分隔符是什么。

相关推荐