如果前一行与模式不匹配,则使用 sed 在多行之间添加文本

如果前一行与模式不匹配,则使用 sed 在多行之间添加文本

我正在努力使用<dl>sed 在定义列表周围添加标签,也许有一种更简单的方法来做到这一点(我很想知道)。

我想在文件中搜索包含 a 的任何行<dt>,但仅当上一行包含时才匹配不是包含<dt><dd>.当找到匹配项时,插入<dl>.

到目前为止我的尝试(根本不匹配):

sed '/^((?!<dt>).)*$/ {
    N
    /<dt>/ {
        s/<dt>/<dl><dt>/
    } 
}' file

还有文件

# TODO #

 * Set up mail transfer agent
 * Reconfigure timezone

```bash
dpkg-reconfigure tzdata
```

# Hardware #
  <dt>RAM</dt>
  <dd>2GB</dd>

# Partitions #

<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>

所有这一切的目的是编写一个解析器,将 moinmoin wiki 标记转换为 Markdown,以便移植到新的 wiki 引擎。目前定义列表是按照以下规则制定的:

sed -i 's/^ \(.*\):: \(.*\)$/  <dt>\1<\/dt>\n  <dd>\2<\/dd>/' file

我希望输出看起来像这样:

# TODO #

 * Set up mail transfer agent
 * Reconfigure timezone

```bash
dpkg-reconfigure tzdata
```

# Hardware #
<dl>
  <dt>RAM</dt>
  <dd>2GB</dd>
</dl>

# Partitions #

<dl>
<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>
</dl>

请注意,我希望尽可能有效的 html。每个开始标签都需要有一个结束标签。

答案1

这可能超出sed您的预期,但我认为这是实现您想要的最好方法sed

这个脚本:

  • 如果该行前面没有其他 、、或 ,则在<dl>包含 的每行之前插入一行。<dt><dt><dd><dl>

  • </dl>如果包含 的行后面的行不包含<dd>,则在包含 的每行之后追加一行。<dd><dd>

sed脚本使用sed hold空格来记住前一行,以便可以<d[tdl]>在插入标签之前检查标签<dl>。它还使用相对寻址ADDR,+N来允许添加结束</dl>标记。需要一种特殊情况来检测 a 是否<dd>位于文件的最后一行并且需要附加</dl>.测试(tT)和分支(b)被广泛用于实现逻辑。

#!/bin/sh

sed '
    /<dt>/ {
        x                  # exchange pattern and hold space
        s/<d[tdl]>//       # subsitutue, just testing for pattern
        g                  # copy hold space back, overwriting pattern space
        t end              # branch to :end if previous subsitution successful
        i \
<dl>
    }

    $ {
        /<dd>/ ! b end     # if <dd> on last line, append </dl>
        a \
</dl>
    }

    /<dd>/,+1 {            # on each line containing <dd> and the line after
        /<dd>/ b end       # if does not contain <dd>, insert </dl>
        i \
</dl>
    }

:end
    h                      # copy pattern space to hold space for next round

' "$@"

该脚本将示例数据修改为如下所示:

[...]

# Hardware #
<dl>
  <dt>RAM</dt>
  <dd>2GB</dd>
</dl>

# Partitions #

<dl>
<dt>`/dev/sda1`</dt>
<dd>/boot</dd>
<dt>`/dev/sda2`</dt>
<dd>/</dd>
</dl>

相关内容