awk Oneliner (二) 文本替换

能有时间空下来写篇博文真是件幸福的事情,这次还接上篇的awk oneliner的内容学习。即然学到该文,如果不提下原文的作者似乎有点说不通。原作者为Peteris Krumins ,蛮厉害的一个家伙。从博文上来看,长的也很俊朗,主要作品为awk oneliner、sed oneliner、perl oneliner系列。

1、将Windows/dos格式的换行(CRLF)转成Unix格式(LF)

<

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

awk '{ sub(/r$/,""); print }'
    <br />

<p style="text-indent:2em;">
    这条语句使用了sub(regex,repl,[string])函数。此函数将匹配regex的string替换成repl,如果没有提供string参数,则$0将会被默认使用。$0的含义在上一篇已经介绍过,代表整行。
</p>
<p style="text-indent:2em;">
    这句话其实是将r删除,然后print语句在行后自动添加一个ORS,也就是默认的n。
</p>
<p style="text-indent:2em;">
    2、将Unix格式的换行(LF)换成Windows/dos格式(CRLF)
</p>
<p style="text-indent:2em;">
awk '{ sub(/$/,"r"); print }'

这句话同样使用了sub函数,它将长度为0的行结束符$替换成r,也就是CR。然后print语句在后面添加一个ORS,使每行最后以CRLF结束。

        <br />

    <p style="text-indent:2em;">
        3、在Windows下,将Unix格式的换行换成Windows/dos格式的换行符
    </p>
    <p style="text-indent:2em;">
awk 1
            <br />

        <p style="text-indent:2em;">
            这条语句不是在所有情况下都可以用,要视使用的awk版本是不是能识别Unix格式的换行而定。如果能,那么它会读出每个句子,然后输出并用CRLF结束。1其实就是{ print }的简写形式。
        </p>
        <p style="text-indent:2em;">
            4、在Windows下,将Windows/dos格式的换行换成unix格式的换行符
        </p>
        <p style="text-indent:2em;">
gawk -v BINMODE="w" '1'
                <br />

            <p style="text-indent:2em;">
                理论上来说,这一行程序应该转换,CRLFs LFs在DOS。标准的GUN文档中提到:在DOS下,awk(和许多其他文本程序)默认将行尾"  r  n“输出为"n","n"输出为"rn" 。一个特别的变量"BINMODE”可以控制这个输出。
            </p>
            <p style="text-indent:2em;">
                我的测试结果显示这个转换并不能完成,所以我认为BINMODE模式并不一定是正确的。所以使用tr更保险一些。
            </p>
            <p style="text-indent:2em;">
tr -d r
                    <br />

                <p style="text-indent:2em;">
                    tr程序可以转换一个设定的字符为另外一个。&nbsp;使用-d选项是删除所有字符并且不做任何转换。在上面的用法用,&nbsp;'r' (CR)字符将被删除。&nbsp;CRLFs 成将会转换为LFs。
                </p>
                <p style="text-indent:2em;">
                    5、删除行首的空格和制表符
                </p>
                <p style="text-indent:2em;">
awk '{ sub(/^[ t]+/,""); print }'

和前面的例子相似,sub函数将[ t]+用空字符串替换,达到删除行首空格的目的。

                        <br />

                    <p style="text-indent:2em;">
                        6、删除行首和行末的空格
                    </p>
                    <p style="text-indent:2em;">
awk '{ gsub(/^[ t]+|[ t]+$/,""); print }'
                            <br />

                        <p style="text-indent:2em;">
                            <span style="white-space:nowrap;">这条语句使用了一个新函数gsub,它和sub的区别在于它会替换句子里面的所有匹配。如果仅仅是要删除字段间的空格,你可以这样</span>
                        </p>
                        <p style="text-indent:2em;">
                            <span style="white-space:nowrap;"></span>&nbsp;
                        </p>
                        <p style="text-indent:2em;">
awk '{ $1=$1; print }'

这是条很取巧的语句,看起来是什么也没作。awk会在你给字段重新赋值的时候对$0重新进行架构,用OFS也就是单个空格分隔所有字段,这样以来所有的多余的空格就消失了。

                                <br />

                            <p style="text-indent:2em;">
                                7、在每行首加5个空格
                            </p>
                            <p style="text-indent:2em;">
awk '{ sub(/^/,"     "); print }'
                                    <br />

                                <p style="text-indent:2em;">
                                    <span style="white-space:nowrap;">同上,sub将行首符替换为5个空格,达到了在行首添加空格的目的。</span>
                                </p>
                                <p style="text-indent:2em;">
                                    8、让内容在79个字符宽的页面上右对齐
                                </p>
                                <p style="text-indent:2em;">
                                    <span style="line-height:24px;background-color:#f8f8f8;font-family:'PT Serif', Georgia, 'Helvetica Neue', Arial, sans-serif;color:#222222;"></span>&nbsp;
                                </p>
                                <p style="text-indent:2em;">
awk '{ printf "%79sn", $0 }'

同上一篇,又使用了printf函数。

                                        <br />

                                    <p style="text-indent:2em;">
                                        9、让内容在79个字符宽的页面上居中对齐
                                    </p>
                                    <p style="text-indent:2em;">
                                        <span style="line-height:24px;background-color:#f8f8f8;font-family:'PT Serif', Georgia, 'Helvetica Neue', Arial, sans-serif;color:#222222;"></span>&nbsp;
                                    </p>
                                    <p style="text-indent:2em;">
awk '{ l=length(); s=int((79-l)/2); printf "%"(s+l)"sn", $0 }'
                                            <br />

                                        <p style="text-indent:2em;">
                                            <span style="white-space:nowrap;">第一句用length函数计算当前行内容的长度,第二句计算行首应该添加多少空格,第三句让内容在s+l宽度靠右对齐。</span>
                                        </p>
                                        <p style="text-indent:2em;">
                                            10、<span style="line-height:24px;background-color:#f8f8f8;font-family:'PT Serif', Georgia, 'Helvetica Neue', Arial, sans-serif;color:#222222;">把foo替换成bar</span>
                                        </p>
                                        <p style="text-indent:2em;">
awk '{ sub(/foo/,"bar"); print }'

同上,sub函数将每行中第一个foo换成了bar。但是,如果想要把每行中所有的foo都替换成bar,你需要使用下面的语句

awk '{ gsub(/foo/,"bar"); print }'
                                                <br />

                                            <p style="text-indent:2em;">
                                                <span style="white-space:nowrap;">另外一种方法就是使用gensub函数</span>
                                            </p>
                                            <p style="text-indent:2em;">
awk '{ $0=gensub(/foo/,"bar",4); print }'
                                                    <br />

                                                <p style="text-indent:2em;">
                                                    这条语句的不同在于它只是将每行第四次出现的foo替换成bar,它的原型是gensub(regex,s,h[,t]),它将字符串t中第h个regex替换成s,如果没有提供t参数,那么默认t就是$0。gensub不是一个标准函数,你只有在GNU Awk或者netBSD带的awk里面才能用到它。
                                                </p>
                                                <p style="text-indent:2em;">
                                                    11、<span style="white-space:nowrap;">在含有baz的行里面,把foo替换成bar</span>
                                                </p>
                                                <p style="text-indent:2em;">
awk '/baz/ { sub(/foo/,"bar") }; {print}'

12、在不含baz的行里,把foo替换成bar

                                                        <br />

                                                    <p style="text-indent:2em;">
                                                        <span style="white-space:nowrap;"></span>&nbsp;
                                                    </p>
                                                    <p style="text-indent:2em;">
awk '!/baz/ { gsub(/foo/, "bar") }; { print }'

跟上一句的差别是用!让搜到baz的返回为假。

                                                            <br />

                                                        <p style="text-indent:2em;">
                                                            <span style="white-space:nowrap;"><span style="white-space:nowrap;">13、<span style="white-space:nowrap;">把scarlet或者ruby或者puce替换成red</span></span></span>
                                                        </p>
                                                        <p style="text-indent:2em;">
                                                            <span style="white-space:nowrap;"><span style="white-space:nowrap;"></span></span>&nbsp;
                                                        </p>
                                                        <p style="text-indent:2em;">
awk '{ gsub(/scarlet|ruby|puce/,"red"); print }'
                                                                <br />

                                                            <p style="text-indent:2em;">
                                                                <span style="white-space:nowrap;">14、<span style="white-space:nowrap;">让文本首位倒置,模仿tac</span></span>
                                                            </p>
                                                            <p style="text-indent:2em;">
                                                                <span style="white-space:nowrap;"></span>&nbsp;
                                                            </p>
                                                            <p style="text-indent:2em;">
awk '{ a[i++] = $0} END { for (j=i-1; j>=0;) print a[j--] }'
                                                                    <br />

                                                                <p style="text-indent:2em;">
                                                                    <span style="white-space:nowrap;">这是one-liner里的一个难点,把每一行的内容放到数组a里面。例如:有三行,分别为“foo”、"bar"、"baz"。数列a包含的内容如下:a[0]="foo",a[1]="bar",a[2]="baz"。当awk执行完所有的行处理,将执行</span><span style="font-family:Helvetica Neue, Arial, Helvetica, sans-serif;color:#222222;font-size:x-small;"><span style="line-height:20px;">END{}操作。END函数将循环输出a数组,如下面的例子:</span></span>
                                                                </p>
                                                                <p style="text-indent:2em;">
                                                                    <span style="white-space:nowrap;"></span>&nbsp;
                                                                </p>
                                                                <p style="text-indent:2em;">
for (j = 2; j >= 0; ) print a[j--]

让变量j从a的最大编号变到0,从后望前逐行输出a里面的内容。

                                                                        <br />

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

 

15、把以结束的行同下一行相接

 

awk '/$/ { sub(/$/,""); getline t; print $0 t; next }; 1'

(/$/,””)函数表达式删除。然后getline函数获取下一行的内容并存入变量t,输出当前行(去掉了)和下一行的相接后的内容。“print $0 t ” 打印原始行和最新读入的行(放入变量t中)。并用next跳过后面的1避免重复输出。如果当前行行末没有,会直接执行1输出。

                                                                            <br />

                                                                        <p style="text-indent:2em;">
                                                                            16、<span style="white-space:nowrap;">将所有用户名排序并输出</span>
                                                                        </p>
                                                                        <p style="text-indent:2em;">
                                                                            <span style="white-space:nowrap;"></span>&nbsp;
                                                                        </p>
                                                                        <p style="text-indent:2em;">
awk -F ":" '{ print $1 | "sort" }' /etc/passwd

这里首先用-F指定了分隔符为冒号,然后用|指定输出的内容逐行pipe给外部程序sort。(这写法真是奇怪)。

                                                                                <br />

                                                                            <p style="text-indent:2em;">
                                                                                <span style="white-space:nowrap;">17、<span style="white-space:nowrap;">将前两个字段倒序输出</span></span>
                                                                            </p>
                                                                            <p style="text-indent:2em;">
                                                                                <span style="white-space:nowrap;"></span>&nbsp;
                                                                            </p>
                                                                            <p style="text-indent:2em;">
awk '{ print $2, $1 }' file

18、将每行里面的前两个字段交换位置

awk '{ temp = $1; $1 = $2; $2 = temp; print }'

因为要输出整行,只好重新给$1和$2赋值,用个临时变量做中转。

                                                                                    <br />

                                                                                <p style="text-indent:2em;">
                                                                                    19、<span style="white-space:nowrap;">删除每行的第二个字段</span>
                                                                                </p>
                                                                                <p style="text-indent:2em;">
awk '{ $2 = ""; print }'

20、把每行的所有字段倒序输出

awk '{ for (i=NF; i>0; i--) printf("%s ", $i); printf ("n") }'

21、删除连续的重复行

awk 'a != $0; { a = $0 }'

前一句省略了action,选择输出整行内容与a不一样的;后一句省略了pattern,把当前行的内容赋值给a。a在这个例子中的左右是记录上一行的内容。

                                                                                        <br />

                                                                                    <p style="text-indent:2em;">
                                                                                        22、<span style="white-space:nowrap;">删除非连续的重复行</span><span style="display:none;" id="__kindeditor_bookmark_start_473__"></span>
                                                                                    </p>
                                                                                    <p style="text-indent:2em;">
                                                                                        <span style="white-space:nowrap;"></span>&nbsp;
                                                                                    </p>
                                                                                    <p style="text-indent:2em;">
awk '!a[$0]++'

把当前行的内容作为数组a的索引,如果a里面已经有了$0的记录,即遇到了重复,pattern的值为0,不输出。

                                                                                            <br />

                                                                                        <p style="text-indent:2em;">
                                                                                            <span style="white-space:nowrap;">23、<span style="white-space:nowrap;">把每5行用逗号相连</span></span>
                                                                                        </p>
                                                                                        <p style="text-indent:2em;">
                                                                                            <span style="white-space:nowrap;"></span>&nbsp;
                                                                                        </p>
                                                                                        <p style="text-indent:2em;">
awk 'ORS=NR%5?",":"n"'

这里在每行输出前,对ORS重新进行定义,如果行号能被5整除则为n,否则为逗号。

                                                                                                <br />

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

 

发表回复

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