如果您知道要交换的两行中每一行的模式,但不知道行的完整内容,则可以执行以下操作:
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
代表换行符,我使用大写的“AND”,因此它很突出,^
是模式空间的开始并且$
是结束):
^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$
为什么我们没有得到“熊/狗/猫”呢?因为由两行组成的正则表达式模式(每行通常由非换行符和后跟换行符组成)使用以下命令锚定在行的末尾:$
所以我们忽略它之前的任何内容。请注意,最后一个换行符是隐含的,实际上并不存在于模式或保留空间中。这就是为什么我不在这里展示它。
现在我们读取“something”并打印它。我们交换。嘿!我们一直在“冒泡”这些东西。分支并打印。由于“dog”位于行的底部(已累积在保留空间中),并且我们在该行之前打印了“某物”,因此效果是我们交换了两行。
无论要交换的两行之前、之间或之后出现多少行,该脚本都将起作用。事实上,如果有多对匹配行,则每对的成员将在整个文件中交换。
正如您所看到的,我只在感兴趣的行中键入一个单词,但任何合适的正则表达式都可以。