交换两行

时间:2010-12-02 05:01:16

标签: sed

如何使用sed HhxgG等命令交换两行?

例如在文件

START
this is a dog
this is a cat
this is something else
END

说我想用“这是别的东西”换掉“这是一只狗”。

这是我到目前为止所做的:

/this is a dog/{
 h # put to hold space 
}
/this is something else/{
 # now i am stuck on what to do.
}

2 个答案:

答案 0 :(得分:22)

如果您知道要交换的两行中的每一行上的模式,但不知道行的全部内容,则可以执行以下操作:

sed -n '                     # turn off default printing
    /dog/{                   # if the line matches "dog"
           h                 # put it in hold space
           :a                # label "a" - the top of a loop
           n                 # fetch the next line
           /something/{      # if it matches "something"
                       p     # print it
                       x     # swap hold and pattern space
                       bb    # branch out of the loop to label "b"
           }                 # done with "something"
                             # if we're here, the line doesn't match "something"
           H                 # append pattern space to hold space
           x                 # swap hold and pattern space
           s/\([^\n]*\)\n\([^\n]*\)$/\2\n\1/    # see below
           x                 # swap hold and pattern space
           ba                # branch to the top of the loop to label "a"
    }                        # done with "dog"
    :b                       # label "b" - outside the loop
                             # print lines that don't match and are outside the pair
    p                        # also prints what had been accumulating in hold space
    ' inputfile

替换模式将“dog”保留在累积行的末尾。它不断交换我们保留在空间中的最后两行,以便“狗”“气泡”到底部。

例如,让我们在“cat”行之后添加另一行,这样过程就会更加清晰。我们将忽略“狗”之前和“某事”之后的界限。我将继续使用我的昵称来引用这些行

this is a dog
this is a cat
there's a bear here, too
this is something else

读取“狗”,然后获取“猫”。一些追加和交换已完成。现在模式空间看起来像这样(\N表示换行符,我使用大写“N”,因此它突出,^是模式空间的开头,$是结束):

^this is a dog\Nthis is a cat$

替换命令查找不是换行符(并捕获它们)的任意数量的字符,后跟换行符,后跟任意数量的非换行符(并捕获它们)在行尾($) )并以换行符相反的顺序替换所有两个捕获的字符串。现在模式空间如下所示:

^this is a cat\Nthis is a dog$

现在我们交换并阅读一个新行。它不是“东西”所以我们做一些追加和交换,现在我们有:

^this is a cat\Nthis is a dog\Nthere's a bear here, too$

我们再次进行替换并得到:

^this is a cat\Nthere's a bear here, too\Nthis is a dog$

为什么我们没有“熊/狗/猫”呢?因为由两行组成的正则表达式模式(通常由非换行符后跟换行符组成)使用$锚定在行的末尾,因此我们忽略了之前的任何内容。请注意,最后一个换行是隐含的,并且实际上不存在于模式或保留空间中。这就是为什么我不在这里展示它。

现在我们读“东西”并打印出来。我们交换。嘿!那些我们一直在“冒泡”的东西。分支和打印。由于“狗”位于线的底部(已经在保留空间中累积)并且我们在那一堆之前打印了“某物”,效果是我们交换了两条线。

无论在要交换的两行之前,之间或之后出现多少行,此脚本都将起作用。实际上,如果有多对匹配行,则每对的成员将在整个文件中交换。

正如你所看到的,我只关注感兴趣的一行中的一个词,但任何合适的正则表达式都可以。

答案 1 :(得分:3)

/this is a dog/{
    h # put line in hold space
    s//this is something else/ # replace with 'this is something else'
    b # branch to end of the script
}
/this is something else/x # swap hold space with pattern space

由于sed是流编辑器,因此您无法使用未来行的内容替换当前行。但是,你可以反过来用你已经看过的一行替换未来的行,这就是我的脚本所做的。

或许另一种方法是使用N命令将每一行附加到模式空间中,然后执行两个s命令来交换两个文字字符串。