迭代查找所有以 X 开头的行,并移至下一行以 Y 开头的行上方

迭代查找所有以 X 开头的行,并移至下一行以 Y 开头的行上方

我有一个这样的文件:

Lorem ipsum dolor sit amet.
Consectetur adipiscing elit.
MATCH1 Quis autem vel!
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
MATCH1 Eum iure reprehenderit?
MATCH2 Qui in ea voluptate
Ut enim ad minim veniam.
Quis nostrud exercitation
TARGET
Sed ut perspiciatis unde.
MATCH1 Nemo enim ipsam voluptatem quia voluptas?
MATCH2 Sit aspernatur aut odit aut fugit.
Omnis iste natus error sit.
Voluptatem accusantium doloremque laudantium
MATCH1 Ut enim ad minima veniam.
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
TARGET
Ut enim ad minima veniam.

我如何找到所有以 开头的行MATCH(可以有一个或多个,但如果有多个则分组在一起)并将它们移动到下一个出现TARGET(总是同一个词,每次只出现一次),并在整个文件中反复重复此过程?处理后的文件将如下所示:

Lorem ipsum dolor sit amet.
Consectetur adipiscing elit.
Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
Ut enim ad minim veniam.
Quis nostrud exercitation
MATCH1 Quis autem vel!
MATCH1 Eum iure reprehenderit?
MATCH2 Qui in ea voluptate
TARGET
Sed ut perspiciatis unde.
Omnis iste natus error sit.
Voluptatem accusantium doloremque laudantium
Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam
MATCH1 Nemo enim ipsam voluptatem quia voluptas?
MATCH2 Sit aspernatur aut odit aut fugit.
MATCH1 Ut enim ad minima veniam.
TARGET
Ut enim ad minima veniam.

任何 GNU/Linux 命令都可以,vi但最好不要使用 Emacs。

多谢!

答案1

sed其“保持空间”功能似乎很适合这项工作。

<file sed '
   /^MATCH/ {H;d}
   /^TARGET$/ {H;s/.*//;x;s/\n//}
   '

它的工作原理如下:

  • MATCH任何不以 开头且不包含 的输入行都不会TARGET触发任何明确的命令并且会被打印,因为这是到达脚本末尾的默认行为。
  • 以以下行开头MATCH

    • 附加到保持空间(H);
    • 接下来,模式空间被删除并开始一个新的循环(读取下一行,脚本重新开始)而不打印任何内容(d)。
  • 包含以下内容的行将TARGET触发以下内容:

    • 该行本身被附加到保持空间 ( H)。此时保持空间保存一个空行(因为其最初为空的内容在第一个 之后变为空行H)、零个或多个带有 的行MATCH以及恰好一行带有 的行TARGET
    • 整个模式空间被替换为无(s/.*//)。
    • 模式空间和保持空间被交换(x)。此时保持空间为空(准备MATCH重新收集 es ),模式空间包含一个空行、MATCH可能有几个 es 和一个TARGET
    • 模式空间中不需要的空行只是最开始的一个换行符。需要将其删除,这就是下一步s要做的事情。
    • 然后脚本继续执行,直到到达末尾。模式空间被打印出来,因为这是到达末尾时的默认行为。

因此基本上,MATCHes 被收集在容纳空间中并打印在上面TARGET

笔记:

  • ^MATCH表示MATCH必须位于行首。MATCH带有前导空格(或制表符等)的将不匹配。^TARGET$不需要前导空格或尾随空格(或制表符等)。如果这不正确,请调整这些模式。
  • MATCH即使没有组合在一起,也会被收集。
  • MATCH在最后一个之后发生的TARGET(或者根本没有TARGET)将不会被打印,因为没有TARGET会触发打印收集它们的保持空间。

相关内容