如果您知道要交换的两行中每一行的模式,但不知道行的全部内容,您可以执行以下操作:
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”,因此我们交换了两行。
无论要交换的两行之前、之间或之后出现多少行,此脚本都将起作用。事实上,如果有多对匹配的行,每对的成员将在整个文件中交换。
如您所见,我只在感兴趣的行中键入一个单词,但任何合适的正则表达式都可以。