awk Oneliner(三) 选择性输出
偷得浮生半日闲,继续拜读学习awk oneliner系列的第三部分——选择性输出。该篇主要讲通过awk的正则输出特定的行的内容。其中很多是模拟grep、sed、head、tail命令的部分。由此也更能表现出awk的强大。
1、输出文件的前10行(模拟 head -n 10 )
1awk ' NR < 11 '
这里同样省略了动作,即为打印输出。匹配模式是变量NR需要小于11,NR即为当前的行号。这个写法很简单,但是有一个问题,在NR大于10的时候,awk其实还是对每行进行了判断,如果文件很大,比如说有上万行,浪费的时间是无法忽略的。所以,更好的写法是
1awk '1; NR = 10 { exit }'
第一句对当前行进行输出。第二句判断是不是已经到了第10行,如果是则退出。
2、输出文件的第一行(模拟 head -n 1 )
1awk 'NR > 1 { exit }; 1'
该句和上面的例子有点像,即NR>1时,则执行退出。
3、输出文件的最后两行(模拟 tail -n 2 )
1awk '{ y=x "n" $0; x=$0}; END { print y }'
的确,这一句看起来确实有些别扭。第一句总是把一个在当前行前面再加上变量x的内容赋值给y,然后用x记录当前行内容。这样的效果是y的内容始终是上一行加上当前行的内容。在最后,输出y的内容。如果仔细看的话,不难发现这个写法是很不高效的,因为它不停的进行赋值和字符串连接,只为了找到最后一行!所以,如果你想要输出文件的最后两行,tail -n 2是最好的选择。
4、输出文件的最后一行(模拟 tail -n 1 )
1awk 'END { print }'
句法方面没什么好说的,print省略参数即是等价于print $0。但是这个语句可能不被非GNU awk的某些awk版本正常执行,如果为了兼容,下面的写法是最安全的:
1awk '{ rec = $0 }; END { print rec }'
5、输出只匹配某些模式的行(模拟 grep )
1awk '/regex/'
7、输出匹配模式的行的上一行,而非当前行
1awk '/regex/ { print x }; { x = $0 }'
将每行数据保存在变量x中,当读到下一行的内容时,变量x此时仍存的是上行的内容。利用该特点,如果出现要匹配的内容时,我们就可以得出我们的结果——上一行的内容。
当我们在第一行的内容中出现"/regex/“中需要匹配的内容时,而我们想要给出一个提示,上面的写法显然不满足这个要求(上面的写法会输出空),这时我们可以利用下面的写法实现:
1awk '/regex/ { print (x=="" ? "match on line 1" : x) }; { x=$0 }'
注意,上面的这个脚本写的很有深度,该句使用了a?b:c的经典用法。作者举的例子是foo?bar:baz,都是一个意思。即“if foo, then bar, else baz ”
8、输出匹配模式的下一行
1awk '/regex/ { getline; print }'
这里使用了getline函数取得下一行的内容并输出。getline的作用是将$0的内容置为下一行的内容,并同时更新NR,NF,FNR变量。如果匹配的是最后一行,getline会出错,$0不会被更新,最后一行会被打印。
9、输出匹配AA或者BB或者CC的行
1awk '/AA|BB|CC/'
当然,这个语句的应用还可以更复杂一点
1awk '{if (/getpeername/||/terminfo/){print $0}if(/getuid()/){getline;print}}'
这是我在“论ssh连接的不安全性”里用的语句,如是匹配“getpeername” 或“terminfo” 则打印本行,如果匹配"getuid()“则输出下一行。提到逻辑或,不得不说下逻辑和,即 and 输出匹配同时包含AA、BB、CC的行
1awk '/AA.*BB.*CC/'
同样是正则,这里的点是连接符号。
10、输出长过65个字符的行
1awk 'length > 64'
length([str])返回字符串的长度,如果参数省略,即是以$0作为参数,括号也可以省略了。同理,我们可以输出少于65个字符的行
1awk 'length < 65'
11、输出从匹配行到最后一行的内容
1awk '/regex/,0'
这里使用了“pattern1,pattern2”的形式来指定一个匹配的范围,其中pattern2这里为0,也就是false,所以一直会匹配到文件结束。
12、输出从第8行输出到第12行
1awk 'NR==8,NR==12'
之前应该也提到过的,NR就是行号。同样输出第52行的内容可以使用:
1awk 'NR==52'
前面也有提到过,这样做会影响效率,要减少不必要的循环可以写为:
1awk 'NR==52 {print;exit}'
13、输出两次正则表达式匹配之间的行
1awk '/regex1/, /regex2/'
原文中举的例子为:
1awk '/Iowa/,/Montana/'
14、删除所有的空行
1awk NF
NF为真即是非空行。另外一种写法是用正则表达式:
1awk '/./'
这个很类似grep .的思路,但是是不如awk NF好的,因为“.”也是可以匹配空格和TAB的。
捐赠本站(Donate)
如您感觉文章有用,可扫码捐赠本站!(If the article useful, you can scan the QR code to donate))
- Author: shisekong
- Link: https://blog.361way.com/awk-oneliner-three/1680.html
- License: This work is under a 知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议. Kindly fulfill the requirements of the aforementioned License when adapting or creating a derivative of this work.