awk Oneliner(三) 选择性输出

2012年7月31日 发表评论 阅读评论

偷得浮生半日闲,继续拜读学习awk oneliner系列的第三部分——选择性输出。该篇主要讲通过awk的正则输出特定的行的内容。其中很多是模拟grep、sed、head、tail命令的部分。由此也更能表现出awk的强大。

1、输出文件的前10行(模拟 head -n 10 )

awk ' NR < 11 '

这里同样省略了动作,即为打印输出。匹配模式是变量NR需要小于11,NR即为当前的行号。这个写法很简单,但是有一个问题,在NR大于10的时候,awk其实还是对每行进行了判断,如果文件很大,比如说有上万行,浪费的时间是无法忽略的。所以,更好的写法是 

awk '1; NR = 10 { exit }'

 第一句对当前行进行输出。第二句判断是不是已经到了第10行,如果是则退出。

2、输出文件的第一行(模拟 head -n 1 )

awk 'NR > 1 { exit }; 1'

该句和上面的例子有点像,即NR>1时,则执行退出。

3、输出文件的最后两行(模拟 tail -n 2 )

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

的确,这一句看起来确实有些别扭。第一句总是把一个在当前行前面再加上变量x的内容赋值给y,然后用x记录当前行内容。这样的效果是y的内容始终是上一行加上当前行的内容。在最后,输出y的内容。如果仔细看的话,不难发现这个写法是很不高效的,因为它不停的进行赋值和字符串连接,只为了找到最后一行!所以,如果你想要输出文件的最后两行,tail -n 2是最好的选择。

4、输出文件的最后一行(模拟 tail -n 1 )

awk 'END { print }'

句法方面没什么好说的,print省略参数即是等价于print $0。但是这个语句可能不被非GNU awk的某些awk版本正常执行,如果为了兼容,下面的写法是最安全的:

awk '{ rec = $0 }; END { print rec }'

5、输出只匹配某些模式的行(模拟 grep )

awk '/regex/'

7、输出匹配模式的行的上一行,而非当前行

awk '/regex/ { print x }; { x = $0 }'

将每行数据保存在变量x中,当读到下一行的内容时,变量x此时仍存的是上行的内容。利用该特点,如果出现要匹配的内容时,我们就可以得出我们的结果——上一行的内容。

当我们在第一行的内容中出现"/regex/"中需要匹配的内容时,而我们想要给出一个提示,上面的写法显然不满足这个要求(上面的写法会输出空),这时我们可以利用下面的写法实现: 

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

注意,上面的这个脚本写的很有深度,该句使用了a?b:c的经典用法。作者举的例子是foo?bar:baz,都是一个意思。即“if foo, then bar, else baz ”


8、输出匹配模式的下一行

awk '/regex/ { getline; print }'

这里使用了getline函数取得下一行的内容并输出。getline的作用是将$0的内容置为下一行的内容,并同时更新NR,NF,FNR变量。如果匹配的是最后一行,getline会出错,$0不会被更新,最后一行会被打印。

9、输出匹配AA或者BB或者CC的行

awk '/AA|BB|CC/'

当然,这个语句的应用还可以更复杂一点

awk '{if (/getpeername/||/terminfo/){print $0}if(/getuid()/){getline;print}}'

这是我在“论ssh连接的不安全性”里用的语句,如是匹配“getpeername” 或“terminfo” 则打印本行,如果匹配"getuid()"则输出下一行。

提到逻辑或,不得不说下逻辑和,即and

输出匹配同时包含AA、BB、CC的行

awk '/AA.*BB.*CC/'

同样是正则,这里的点是连接符号。

10、输出长过65个字符的行

awk 'length > 64' 

length([str])返回字符串的长度,如果参数省略,即是以$0作为参数,括号也可以省略了。

同理,我们可以输出少于65个字符的行

awk 'length < 65' 

11、输出从匹配行到最后一行的内容

awk '/regex/,0'

这里使用了“pattern1,pattern2”的形式来指定一个匹配的范围,其中pattern2这里为0,也就是false,所以一直会匹配到文件结束。

12、输出从第8行输出到第12行

awk 'NR==8,NR==12'

之前应该也提到过的,NR就是行号。

同样输出第52行的内容可以使用:

awk 'NR==52' 

前面也有提到过,这样做会影响效率,要减少不必要的循环可以写为:

awk 'NR==52 {print;exit}'

13、输出两次正则表达式匹配之间的行

awk '/regex1/, /regex2/' 

原文中举的例子为:

awk '/Iowa/,/Montana/' 

14、删除所有的空行

awk NF 

NF为真即是非空行。另外一种写法是用正则表达式:

awk '/./' 

这个很类似grep .的思路,但是是不如awk NF好的,因为“.”也是可以匹配空格和TAB的。

 




本站的发展离不开您的资助,金额随意,欢迎来赏!

You can donate through PayPal.
My paypal id: itybku@139.com
Paypal page: https://www.paypal.me/361way

分类: perl/php/python/gawk/sed 标签:
  1. 本文目前尚无任何评论.