Sed: como substituir o símbolo nextline \ n em arquivos de texto?

3

Eu preciso corrigir um erro e substituir a segunda tag </time> por </tags> em um arquivo XML com a seguinte estrutura:

<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>
<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>

Estou tentando fazer isso usando sed e, como tenho 2% de tag de fechamento</time> por item, minha ideia é substituir </time><geo> por </tags><geo> .

No entanto, há um símbolo de próxima linha no meio, por isso estou usando \n , mas não funciona:

sed 's/time>\n<geo>/tags>\n<geo>/g' old.xml > new.xml
    
por aneuryzm 23.04.2011 / 16:35

3 respostas

4

Sed processa sua entrada linha por linha, portanto, um caractere de nova linha nunca aparecerá espontaneamente na entrada. O que você poderia fazer é colocar as linhas que terminam em </time em espera; então, se a próxima linha começar com <geo> , faça a substituição na linha anterior. (Isso é possível em sed, usando o "espaço de espera", mas eu recomendo mudar para awk ou perl quando você precisar do espaço de espera.)

No entanto, considerando sua entrada de amostra, você pode alterar apenas </time> para </tags> quando a linha começar com <tags> .

sed -e '/^<tags>/ s!</time>$!</tags>!'
    
por 23.04.2011 / 16:56
2

Embora talvez a solução para o seu problema possa ser facilmente alcançada por outros meios, a resposta à sua pergunta é simples. sed , por padrão, trabalha uma linha de cada vez em 2 buffers - um persistente entre os ciclos de linha chamado h old space e um atualizado pelo menos uma vez por ciclo chamado espaço padrão - e o segundo é onde todas as edições são realizado.

O futuro pode ser obtido de duas maneiras - você pode salvar linhas antigas e ficar atrás do ciclo de linha para fazer melhor uso dos comandos para trocar e comparar os buffers. Isso envolve primitivos de comando como [hH] old, [gG] et, e x change - que salvam, copiam e trocam o buffer de suspensão respectivamente - e sobrescrevem formulários em minúsculas e formulários em maiúsculas anexados ao buffer de destino.

Ou você pode trabalhar linhas futuras em um algoritmo de edição constante no qual você remove sempre quantas linhas de entrada você ler por ciclo. Este último seria minha preferência aqui - especialmente porque sed torna isso muito fácil e eficiente - especialmente com os comandos N;P;D .

Aqui está uma demonstração usando seus dados de exemplo:

sed '$!N;s/ime\(>\n<geo\)/ags/;P;D
'  <<\IN
<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>
<time>20260664</time>
<tags>substancesummit ss</time>
<geo>asdsadsa</geo>
IN
N ext, P rint e D elete, como suas contrapartes em minúscula n;p;d obtêm a próxima linha de entrada, impressão e exclusão em / do espaço padrão, respectivamente. Ao contrário de suas contrapartes minúsculas (se um pouco menos ao contrário do caso de N ) , estas três trabalham em limites de nova linha em vez de espaço de padrão como um todo.

  • N acrescentará a próxima linha de entrada ao espaço padrão seguindo um caractere \n ewline.
  • P será impresso apenas até o primeiro caractere% ww%% ewline no espaço padrão.
  • \n excluirá apenas até e incluindo o primeiro D ewline em espaço de padrão antes de sair do script para o ciclo atual e enfileirar o próximo com o que permanecer no espaço padrão ou, se nada permanecer após sua ação de exclusão, com a próxima linha aguardando a entrada como de costume.

Esses três podem trabalhar juntos para expandir a janela de edição de \n em um arquivo de maneira simples e eficiente - sed desliza por uma impressão de arquivo por ciclo somente a mais antiga de uma série de linhas que exclui e repõe consistentemente de acordo com instruções do criador de scripts - o que deixa o sed responsável pelo ciclo da linha.

E uma próxima linha de lookahead é facilmente expandida. Se você quisesse uma janela de espaço padrão de 4 linhas em todo o script, você poderia fazer:

sed -e '1{N;N' -e '};N;...;P;D'

... ou, talvez mais útil ...

sed -e ':next
    $!{/\(.*\n\)\{3\}/!{
        N;b next' -e '}
    };...cmds...;P;D'

... em que sed apenas desenha em uma linha de entrada - e continua a fazê-lo até ter o suficiente antes de executar qualquer outro comando - se houver menos de três sed caracteres de ewline no espaço padrão e o atual linha não é a última. Isso ocorre independentemente do que as edições feitas pelos comandos subsequentes possam fazer.

    
por 30.11.2014 / 22:11
0

Para resposta literária, a questão:

Eu resolvo este problema (o texto para editar abrange múltiplas linhas) por um pequeno truque:

cat input.txt | tr '\n' '@' | sed -e 's/txt@iam@interestedin/iaminterested@intxt/g' | tr '@' '\n' > output.txt

A única coisa que você precisa ter certeza é que o caractere ao qual você substitui a nova linha ainda não existe em sua entrada.

    
por 30.11.2014 / 19:29