Sed 循环
Sed - 循环与分支
Section titled “Sed - 循环与分支”与传统的编程语言一样,sed 提供了控制执行流程的机制,特别是通过 label(标签)和分支命令。这使得创建 sed 命令的循环和条件执行成为可能,从而实现更复杂的文本处理逻辑。
标签(Labels)
Section titled “标签(Labels)”sed 中的 label(标签)标记了脚本中的一个特定点。然后你可以使用分支命令跳转到这个 label。label 通过冒号(:)后跟标签名称来定义。标签名称可以包含除换行符之外的任何字符。
标签定义示例::mylabel:start_loop:process_data:end_section分支命令(Branching Commands)
Section titled “分支命令(Branching Commands)”sed 提供了两个主要的分支命令:
b [label](Branch): 无条件跳转到指定的label。如果未提供label,sed会跳转到脚本的末尾,有效地开始读取新一行的下一个循环(如果还有输入行)。t [label](Test and Branch): 仅当自上次读取输入行或执行上次t命令以来,s///(替换)命令成功进行了替换时,才跳转到label。如果未提供label,它会跳转到脚本的末尾。这对于循环直到满足某个条件(没有更多的替换发生)非常有用。
示例:使用循环和分支处理成对的行
Section titled “示例:使用循环和分支处理成对的行”我们考虑一个 books.txt 文件,其中每本书的书名和作者分别在连续的两行上。我们希望将它们合并到一行,用逗号分隔,然后仅当合并后的行包含 “Paulo” 时,才在行前加上一个连字符(- )。
假设 `books.txt` 文件内容如下:A Storm of SwordsGeorge R. R. MartinThe Two TowersJ. R. R. TolkienThe AlchemistPaulo CoelhoThe Fellowship of the RingJ. R. R. TolkienThe PilgrimagePaulo CoelhoA Game of ThronesGeorge R. R. Martin实现此功能的 sed 脚本:
$ sed -n ' \N; # 将下一行附加到 pattern space,创建 'line1\nline2' s/\n/, /; # 将换行符替换为 ', ' /Paulo/!b PrintLine; # 如果找不到 'Paulo',则跳转到 PrintLine s/^/- /; # 如果找到了 'Paulo'(未发生跳转),则在行前添加 '- ':PrintLine p # 打印(可能已修改的)pattern space' books.txt输出:
A Storm of Swords, George R. R. MartinThe Two Towers, J. R. R. Tolkien- The Alchemist, Paulo CoelhoThe Fellowship of the Ring, J. R. R. Tolkien- The Pilgrimage, Paulo CoelhoA Game of Thrones, George R. R. Martinsed -n '...' books.txt:-n选项抑制sed的自动打印行为。我们将使用p命令显式地打印。N;: 这是Next 命令。它将下一行输入附加到pattern space(模式空间)中,并用换行符(\n)分隔。因此,如果pattern space原来包含 “Title”,执行N后它将包含 “Title\nAuthor”。这个命令隐式地创建了一个处理成对行的循环。s/\n/, /;:substitute(替换)命令将嵌入的换行符(由N引入)替换为一个逗号和一个空格。此时pattern space变为 “Title, Author”。/Paulo/!b PrintLine;: 这是一个条件分支。/Paulo/是一个匹配包含 “Paulo” 的行的地址。!否定了这个条件,所以它的意思是“如果pattern space不包含 ‘Paulo’”。如果条件为真,b PrintLine命令将分支(跳转)到:PrintLine标签。如果条件为假(即pattern space确实包含 “Paulo”),则继续执行下一个命令。s/^/- /;: 这个替换命令只有在前一个分支未被执行时才会到达(这意味着找到了 “Paulo”)。它在pattern space的开头(^)添加一个连字符和一个空格(-)。:PrintLine: 这定义了PrintLine标签。p:print 命令打印当前pattern space的内容。
这个脚本演示了如何使用 N 命令一起处理多行,以及如何使用带标签的 b 命令根据模式匹配来控制执行流程。原始示例使用了 h;n;H;x,这是另一种使用 hold space(保持空间)连接行的方式,更适合处理复杂的多行记录。对于连接相邻的行,N 命令通常更简单。
使用保持空间的替代方法(更接近原始示例): 原始示例使用 h;n;H;x 来组合行。这个序列的工作方式如下:
h: 将pattern space(当前行,例如 “Title”)复制到hold space。n: 将下一行(例如 “Author”)读入pattern space(覆盖 “Title”)。H: 将pattern space(“Author”)附加到hold space。此时hold space变为 “Title\nAuthor”。x: 交换pattern space和hold space。现在pattern space包含 “Title\nAuthor”。
然后,脚本将类似地继续:s/\n/, /; /Paulo/!b Print; s/^/- /; :Print; p。
选择使用 N 还是 h;n;H;x 取决于具体的的多行处理任务。N 对于固定的行对更简单,而 hold space 操作对于复杂的场景提供了更大的灵活性。
循环和分支,特别是与 hold space 操作结合使用时,是 sed 最高级的功能之一。它们需要仔细思考,但为复杂的文本转换提供了强大的能力。