awk Oneliner(三) 选择性输出

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

<

p style=”text-indent:2em;”>
1、输出文件的前10行(模拟 head -n 10 )

awk ' NR < 11 '

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

<

p style="text-indent:2em;">

awk '1; NR = 10 { exit }'

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

            <br />

        <p style="text-indent:2em;">
            2、输出文件的第一行(模拟 head -n 1 )<br />
            <p style="text-indent:2em;">
awk 'NR > 1 { exit }; 1'
                <p style="text-indent:2em;">
                    该句和上面的例子有点像,即NR>1时,则执行退出。
                </p>
                <p style="text-indent:2em;">
                    3、输出文件的最后两行(模拟 tail -n 2 )<br />
                    <p style="text-indent:2em;">
awk '{ y=x "n" 0; x=0}; END { print y }'
                        <p style="text-indent:2em;">
                            的确,这一句看起来确实有些别扭。第一句总是把一个在当前行前面再加上变量x的内容赋值给y,然后用x记录当前行内容。这样的效果是y的内容始终是上一行加上当前行的内容。在最后,输出y的内容。如果仔细看的话,不难发现这个写法是很不高效的,因为它不停的进行赋值和字符串连接,只为了找到最后一行!所以,如果你想要输出文件的最后两行,tail -n 2是最好的选择。
                        </p>
                        <p style="text-indent:2em;">
                            4、输出文件的最后一行(模拟 tail -n 1 )<br />
                            <p style="text-indent:2em;">
awk 'END { print }'
                                <p style="text-indent:2em;">
                                    句法方面没什么好说的,print省略参数即是等价于print $0。但是这个语句可能不被非GNU awk的某些awk版本正常执行,如果为了兼容,下面的写法是最安全的:
awk '{ rec = $0 }; END { print rec }'
                                        <br />

                                    <p style="text-indent:2em;">
                                        5、输出只匹配某些模式的行(模拟 grep )<br />
                                        <p style="text-indent:2em;">
awk '/regex/'
                                                <br />

                                            <p style="text-indent:2em;">
                                                7、输出匹配模式的行的上一行,而非当前行
                                            </p>
                                            <p style="text-indent:2em;">
awk '/regex/ { print x }; { x = $0 }'
                                                    <br />

                                                <p style="text-indent:2em;">
                                                    将每行数据保存在变量x中,当读到下一行的内容时,变量x此时仍存的是上行的内容。利用该特点,如果出现要匹配的内容时,我们就可以得出我们的结果——上一行的内容。
                                                </p>
                                                <p style="text-indent:2em;">
                                                    当我们在第一行的内容中出现"/regex/"中需要匹配的内容时,而我们想要给出一个提示,上面的写法显然不满足这个要求(上面的写法会输出空),这时我们可以利用下面的写法实现:&nbsp;
                                                </p>
                                                <p style="text-indent:2em;">
awk '/regex/ { print (x=="" ? "match on line 1" : x) }; { x=$0 }'

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

                                                        <br />

                                                    <p style="text-indent:2em;">
                                                        <br />

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

awk '/regex/ { getline; print }'

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

                                                                <br />

                                                            <p style="text-indent:2em;">
                                                                9、输出匹配AA或者BB或者CC的行<br />
                                                                <p style="text-indent:2em;">
awk '/AA|BB|CC/'
                                                                    <p style="text-indent:2em;">
                                                                        当然,这个语句的应用还可以更复杂一点
                                                                    </p>
                                                                    <p style="text-indent:2em;">
awk '{if (/getpeername/||/terminfo/){print $0}if(/getuid()/){getline;print}}'
                                                                            <br />

                                                                        <p style="text-indent:2em;">
                                                                            这是我在“论ssh连接的不安全性”里用的语句,如是匹配“getpeername” 或“terminfo” 则打印本行,如果匹配"getuid()"则输出下一行。
                                                                        </p>
                                                                        <p style="text-indent:2em;">
                                                                            提到逻辑或,不得不说下逻辑和,即and
                                                                        </p>
                                                                        <p style="text-indent:2em;">
                                                                            输出匹配同时包含AA、BB、CC的行
awk '/AA.*BB.*CC/'
                                                                                <br />

                                                                            <p style="text-indent:2em;">
                                                                                同样是正则,这里的点是连接符号。
                                                                            </p>
                                                                            <p style="text-indent:2em;">
                                                                                10、输出长过65个字符的行
                                                                            </p>
                                                                            <p style="text-indent:2em;">
awk 'length > 64' 
                                                                                <p style="text-indent:2em;">
                                                                                    length([str])返回字符串的长度,如果参数省略,即是以$0作为参数,括号也可以省略了。
                                                                                </p>
                                                                                <p style="text-indent:2em;">
                                                                                    同理,我们可以输出少于65个字符的行
                                                                                </p>
                                                                                <p style="text-indent:2em;">
awk 'length < 65' 
                                                                                    <p style="text-indent:2em;">
                                                                                        11、输出从匹配行到最后一行的内容
                                                                                        <p style="text-indent:2em;">
awk '/regex/,0'
                                                                                            <p style="text-indent:2em;">
                                                                                                这里使用了“pattern1,pattern2”的形式来指定一个匹配的范围,其中pattern2这里为0,也就是false,所以一直会匹配到文件结束。
                                                                                                <p style="text-indent:2em;">
                                                                                                    12、输出从第8行输出到第12行
                                                                                                    <p style="text-indent:2em;">
awk 'NR==8,NR==12'
                                                                                                        <p style="text-indent:2em;" align="left">
                                                                                                            之前应该也提到过的,NR就是行号。
                                                                                                        </p>
                                                                                                        <p style="text-indent:2em;" align="left">
                                                                                                            同样输出第52行的内容可以使用:
                                                                                                            <p style="text-indent:2em;">
awk 'NR==52' 
                                                                                                                <p style="text-indent:2em;">
                                                                                                                    前面也有提到过,这样做会影响效率,要减少不必要的循环可以写为:
                                                                                                                    <p style="text-indent:2em;">
awk 'NR==52 {print;exit}'
                                                                                                                        <p style="text-indent:2em;">
                                                                                                                            13、输出两次正则表达式匹配之间的行
                                                                                                                            <p style="text-indent:2em;">
awk '/regex1/, /regex2/' 
                                                                                                                                <p style="text-indent:2em;">
                                                                                                                                    原文中举的例子为:
                                                                                                                                </p>
                                                                                                                                <p style="text-indent:2em;">
awk '/Iowa/,/Montana/' 
                                                                                                                                    <p style="text-indent:2em;">
                                                                                                                                        14、删除所有的空行
                                                                                                                                        <p style="text-indent:2em;">
awk NF 
                                                                                                                                            <p style="text-indent:2em;">
                                                                                                                                                NF为真即是非空行。另外一种写法是用正则表达式:
                                                                                                                                                <p style="text-indent:2em;">
awk '/./' 
                                                                                                                                                    <p style="text-indent:2em;">
                                                                                                                                                        这个很类似grep .的思路,但是是不如awk NF好的,因为“.”也是可以匹配空格和TAB的。
                                                                                                                                                    </p>
                                                                                                                                                    <p style="text-indent:2em;">
                                                                                                                                                        &nbsp;
                                                                                                                                                    </p>

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注