【问题标题】:Swapping two lines交换两条线
【发布时间】:2016-03-06 09:37:31
【问题描述】:

如何使用 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.
}

【问题讨论】:

    标签: sed


    【解决方案1】:

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

    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”行之后再放一行,这样流程会更清晰一些。我们将忽略“dog”之前和“something”之后的行。我将继续使用我的昵称引用这些行

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

    读取“Dog”,然后获取“cat”。完成了一些附加和交换。现在模式空间看起来像这样(\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$
    

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

    现在我们读取“某物”并打印它。我们交换。嘿!有我们一直在“冒泡”的东西。分支和打印。由于“dog”位于行的底部(已累积在保持空间中)并且我们在该行之前打印了“something”,因此我们交换了两行。

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

    如您所见,我只在感兴趣的行中键入一个单词,但任何合适的正则表达式都可以。

    【讨论】:

      【解决方案2】:
      /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 命令来交换两个文字字符串。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多