Chinaunix首页 | 论坛 | 博客
  • 博客访问: 330572
  • 博文数量: 53
  • 博客积分: 1132
  • 博客等级: 少尉
  • 技术积分: 451
  • 用 户 组: 普通用户
  • 注册时间: 2010-03-18 14:22
文章分类

全部博文(53)

文章存档

2014年(1)

2013年(11)

2012年(17)

2011年(16)

2010年(8)

分类:

2011-12-03 09:23:06

Awk one-liners explained3

 

终于到了基础部分的最后一篇,这篇内容不算多,加油吧。

    第三篇:有选择的打印行

 

45、打印文件的前5行(相当于head -5

#more file

a b c

d e f

g h i

j k l

m n o

p q r

s t u

v w x

y z

# awk 'NR < 6' file

a b c

d e f

g h i

j k l

m n o

前面也提到过,NR的意思是只当前文件的行号,每读一行,awk会自动给NR增加1。这个命令只有一个模式NR <6,而没有{动作},默认为{print $0}。模式中指的是匹配行号NR<6(即第一到第五行),即把文件file的第一到第五行打印出来。从第六行开始,awk检测到NR>=6,因此不执行动作{print}

这个程序的效率不高,因为当NR>=6时,awk会继续遍历文件直到结束,但其实后面做的都是无用功,因为不执行任何动作。以下是改进的程序

# awk '1; NR == 5 { exit }' file

a b c

d e f

g h i

j k l

m n o

语句NR==5{exit}能够确保文件遍历到第五行的时候立刻停止程序。当文件的NR小于5的时候,语句“1”相当于{print},因此当NR<=5的时候,awk打印出所有匹配的行,然后程序停止。当文件的行数非常多的时候,提高执行的效率。

46、打印文件的第一行(head -1

# awk 'NR > 1 { exit }; 1' file

a b c

和前面的例子一样,只有当NR==1的时候模式才匹配,读第一行的时候,模式不匹配,直接到第二个语句“1”,也就是{print},打印第一行,读到第二行的时候NR=2,匹配模式,执行{exit},退出了awk,完毕。

47、打印文件的倒数2行(tail -2

# awk '{ y=x "\n" $0; x=$0 }; END { print y }' file

v w x

y z

这个awk程序时怎么样工作的呢,首先看第一个语句{ y=x "\n" $0; x=$0 },这个语句只有动作没有模式,因此对所有行都执行动作。读取第一行的时候,变量y被赋值为”\nline1”(因为x没有被定义),然后定义变量x”line1”. 读取第二行的时候,变量y被赋值为”line1\nline2”,变量x=line2。依次类推,读取第三行的时候y=”line2\nline3”,x=”line3”,一直到读取最后一行的时候,y=”lineN-1\nlineN”,x=”lineN”。这样变量y就包含了最后两行的内容,通过END{print y}将其打印出来。

仔细想想这个程序,大家能够看得出来这个程序的效率也是非常低的。Awk程序读取了整个文件的所有行,但是最后的动作无非是打印出来最后两行。不行的是在awk中没有像seek()这样的函数,因此无法在文件中找出最后两行(用tail可以找出),因此如果要打印出文件最的最后几行,还是把这个任务交给tail吧。

48、打印文件的最后一行(tail -1

# awk 'END { print }' file

y z

这个程序有可能会生效也有可能不生效。它只有在文件遍历完以后,包含最后一行记录的$0没有被初始化的情况下才能生效。END{}模块是在所有记录都读取完以后执行,这里的{print}原意是想打印出文件结尾的$0,而这个变量是有可能被重置的。

而这个程序生效与否取决于你的awk的版本和执行过程,GNUawk是可以执行成功的,但是在nawk 或者xpg4/bin/awk下貌似不能执行成功

PS:我用nawkxpg4/bin/awk试过了,确实不会生效,也就是文件遍历完以后,$0被重置了。

49、打印匹配正则表达式/regex/的行(相当于grep的作用)

#awk '/f/' file

d e f

这个程序使用正则表达式/f/作为模式部分,匹配正则表达式则执行默认的动作{print},即打印匹配f的所有行。

50、打印不匹配正则表达式/regex/的行(相当于grep -v

# awk '!/f/' file

a b c

g h i

j k l

m n o

p q r

s t u

v w x

y z

正则表达式可以在表达式前面加上!来取反,匹配f的行在!的作用下变成了假,而不执行{print}的动作,相反不匹配f的行在!的作用下为真,执行动作{print},打印记录。

51、打印匹配正则表达式/regex/所在行的前一行。

# awk '/f/ { print x }; { x=$0 }' file

a b c

这个程序总是把当前的行赋值给变量x,直到有行匹配f,这时候打印变量x,而这个x正好是上一行的$0.因此打印出上一行。

如果当正则表达式匹配第一行的时候,这个程序就不起作用,因为没有前一行,x没有被定义。这时候我们可能会想要打印出”match on line1”(匹配第一行),可以用下面程序实现

# awk '/a/ { print (x=="" ? "match on line 1" : x) }; { x=$0 }' file               

match on line 1

这个语句测试变量x是否被定义,只有第一次使用x的时候x才为空,这样的话讲打印出”match on line1”。否则将打印出变量x的值,也就是读取上一行的时候被赋值给x$0

注意到awk中使用了一个三元运算符(x==””?”match on line1”:”x”)。它的意思是ifx==””),前面print的就是”match on line1”,不为空则print x

PS:三元运算符(a?b:c)是从c中借鉴过来的,意思是if a 为真,则belse c

52、打印匹配正则表达式/regex/所在行的下一行。

#awk '/a/ { getline; print }' file

d e f

这个awk程序在匹配/a/的所有行调用了getline()函数,getline获取的是当前行的下一行记录$0(同时更行变量NF,NR,FNR),然后{print}打印出来的也是下一行的$0,这样就实现了打印匹配行的下一行。

    如果刚好是最后一行匹配/a/,那么getline应该会返回一个错误代码,应为已经没有下一行了,但是实际上getline得到就是最后一行并且print出来

53、打印匹配/a/,/f/,/k/的行

# awk '/a|f|k/' file

a b c

d e f

j k l

这个语句的特点在于使用了扩展的正则表达式,意思是任意行只要匹配a,f,或k,都将执行默认的{print}动作,打印出相应的行。

54、打印出包含abc的行(顺序必须是abc

# awk '/a.*b.*c/' file

a b c

这个语句同样是在正则表达式上做手脚,模式是这样理解的,匹配的行中包含一个a,然后是任意字符(也可以是空),然后是b,然后是任意字符,然后是c,最后打印出这样的行。

55、打印长度大于64个字符的行

# awk 'length > 64' file

模式部分使用的是length()函数,完整的模式应该是lengthvar),函数的作用是返回字符串var的长度,如果不指定var,默认将使用$0。因此这个语句在模式部分判断是否有超过64个字符的行,如果有,打印出来,没有则不执行任何动作。

56、打印长度小于64个字符的行

#awk 'length < 64' file

a b c

d e f

g h i

j k l

m n o

p q r

s t u

v w x

y z

这个没什么好讲的,大家肯定都能理解。

57、打印出从匹配正则表达式的行到文件末尾的部分区域

# awk '/s/,0' file

s t u

v w x

y z

这个awk程序使用的匹配模式是模式1,模式2”这种形式,意思是从模式1匹配的行开始,一直到模式2匹配的行结束,对区间内所有的行执行{动作}。在这个例子中,模式1,是指包含s的行,模式20,也就是假,所以这例子也就是说从包含s的行开始,一直到文件结束,把这些行打印出来。

PS:由于0是假,不可能被匹配,因此模式匹配的行是从包含s的那行直到文件结尾

58、打印从第三行到第六行

# awk 'NR==3,NR==6' file

g h i

j k l

m n o

p q r

    这个例子同样使用了多个模式匹配的形式,模式1和模式2分别为NR==3,NR==6,即第三行和第六行,因此匹配36行的记录为3456行,打印出来。

59、打印第五行

# awk 'NR==5' file

m n o

这个例子测试当前行是否是第五行,如果是第五行则打印出来。

其实正确的方法应该是匹配到第五行以后要立即停止awk程序,提高运行效率。

# awk 'NR==5{print;exit}' file

m n o

这个程序在遍历到第5行的时候,把第五行打印出来,然后强制退出awk,省去了读取其他行的时间,提高了效率。

60、打印从匹配正则表达式1的行到匹配正则表达式2的行内的所有行。

# awk '/a/,/k/' file

a b c

d e f

g h i

j k l

前面讲过这个模式匹配的是从包含a的行到包含k的行,之间所有的行。然后打印出来。

  PS:有个地方需要注意,文件中可能有多个区间都匹配这个模式,比如

e

a

b

k

a

c

k

   这种情况下的输出为

a

b

k

a

c

k

    如果文件为

e

a

b

k

s

a

b

   输出为

   

a

b

k

a

b

   这是因为当模式第二次匹配到a的时候,下面没有行再匹配k,默认匹配到文件结尾。

61、删除文件中所有的空行

#more file

a b c

 

d e f

g h i

 

 

j k l

m n o

# awk NF file

a b c

d e f

g h i

j k l

m n o

  这个例子使用了域的个数(NF)作为模式部分,因为空行中域的个数为0,因此不执行默认的{print}动作,还有一个命令可以实现这个功能

# awk '/./' file

a b c

d e f

g h i

j k l

m n o

这里使用的是正则表达式/./,它匹配的是任何包含字符的行,空行不包含字符,所以不被打印。

 

Awk的基本3部曲到这里就结束了,希望对新手们有所帮助。。谢谢了

 

 

 

 

 

阅读(1108) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~