Adicione texto entre várias linhas com sed se a linha anterior não corresponder ao padrão

1

Eu estou lutando para adicionar <dl> tags em torno de uma lista de definição com sed, e talvez haja uma maneira mais fácil de fazê-lo (eu adoraria saber).

Eu gostaria de pesquisar em um arquivo por qualquer linha que contenha um <dt> , mas só coincida se a linha anterior não contiver <dt> ou <dd> . Quando uma correspondência for encontrada, insira um <dl> .

Minha tentativa até agora (que não corresponde a todos):

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

E o arquivo

# 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>

O objetivo de tudo isso é escrever um analisador que converta a marcação wiki moinmoin em markdown, para portar para um novo mecanismo wiki. A lista de definições é feita atualmente com a seguinte regra:

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

Eu gostaria que a saída fosse assim:

# 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>

Note que eu gostaria de ter um html válido o máximo possível. É necessário que haja uma tag de fechamento para cada tag de abertura.

    
por stooj 08.12.2015 / 01:27

1 resposta

3

Isso pode ser mais sed do que o esperado, mas acho que essa é a melhor maneira de realizar o que você deseja com sed .

Este script:

  • Insere uma linha <dl> antes de cada linha que contém <dt> , se nenhum outro <dt> , <dd> ou <dl> precedeu a linha.

  • Anexa uma linha </dl> após cada linha contendo <dd> , se a linha após a linha contendo <dd> não contiver <dd> .

Este script sed usa o espaço sed hold para lembrar a linha anterior para que possa verificar as tags <d[tdl]> antes de inserir a tag <dl> . Ele também usa o endereçamento relativo ADDR,+N para permitir a adição da tag </dl> de fechamento. Um caso especial é necessário para detectar se um <dd> está na última linha do arquivo e precisa de um </dl> anexado. Testes ( t e T ) e ramificação ( b ) são usados extensivamente para implementar a lógica.

#!/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

' "$@"

Este script modifica os dados da amostra para ficarem assim:

[...]

# 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>
    
por 08.12.2015 / 06:44