Назад | Перейти на главную страницу

SED заменяет несколько строк

Я пытаюсь найти эти три строчки:

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

и замените их на:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

Когда я пытаюсь

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Не находит, тоже пробовал вставить \ n, но все равно не вышло:

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

Они не вызывают ошибок, просто не раскомментируют строку. Любой совет поможет спасибо!

Sed работает построчно. Его можно заставить работать с несколькими линиями, но он не был разработан таким образом - и, на мой взгляд, это определенно видно, когда вы пытаетесь использовать это. Но если вы решите пойти по этому пути, вам, вероятно, придется использовать регистры. Ознакомьтесь с некоторыми решениями https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n чтобы увидеть, как это можно сделать.

Я предпочитаю использовать perl вместо sed для такого рода задач (я имею в виду многострочную). Шаблон, который вы должны добавить перед поиском и заменой (BEGIN...) не очевидно, но мне кажется, что регулярное выражение чище:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

Или, используя группировку, чтобы сократить выражение и позволить вам использовать там регулярное выражение:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

Он должен работать как с вхождениями с новой строкой, так и без нее между маркерами комментариев и кодом, который нужно раскомментировать.

Адаптировано из:

https://stackoverflow.com/questions/1030787/multiline-search-replace-with-perl

sed читает каждую строку по очереди, поэтому он никогда не будет соответствовать многострочному шаблону, если вы не подтолкнете его в правильном направлении. В N команда считывает одну строку из ввода и добавляет ее в пространство шаблонов.

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

Возможно, если вам нужна другая команда, кроме s, тогда вам следует отказаться от sed и перейти на awk или perl. Вот немного более гибкий фрагмент Perl, который справляется с многострочными комментариями в более общем виде.

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml

Вот описание многострочных команд в SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

Это боль в заднице. Вы можете последовать совету Эдуардо и использовать perl -i -p -e вместо.

  • /<\!--/ : соответствующая строка
  • :X : это метка для команды ветви "b"
  • /-->/ : соответствующая строка
  • s@...@...@p : strip "<! -", "->" и распечатать результат
  • d : удалить шаблонное пространство и начать новый цикл
  • N : если не совпадает с / -> /, добавьте строку
  • bX : переход к: метке X
  • p : просто напечатайте строку, которая не соответствует / <! - /

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

и этот второй метод представляет собой простую дословную замену копирования и вставки для обычных текстовых файлов небольшого размера (требуется файл сценария оболочки)

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files