САС заменить через несколько строк

11

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

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

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

Дуг Молинье
источник

Ответы:

6

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
Жиль "ТАК - перестань быть злым"
источник
6

Sed работает построчно. Это может быть сделано для работы на нескольких линиях, но это не было разработано таким образом - и, на мой взгляд, это определенно показывает, когда вы пытаетесь использовать таким образом. Но если вы решите пойти по этому пути, вам, вероятно, придется использовать регистры. Ознакомьтесь с некоторыми решениями по адресу /programming/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

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

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

/programming/1030787/multiline-search-replace-with-perl

Эдуардо Иванец
источник
Спасибо за вашу помощь, похоже, это боль, я решил использовать обходной путь
Даг Молинью
3

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

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

Hyppy
источник
Я не буду ссылаться на несанкционированные копии материалов, защищенных авторским правом.
Марк Вагнер
1
  • /<\!--/ : совпадающая строка
  • :X : это метка для команды ветвления "b"
  • /-->/ : совпадающая строка
  • s@...@...@p : раздеться "<! -", "->" и вывести результат
  • 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
mug896
источник
1) Спасибо за ваш ответ. 2) Вставлять только фрагменты кода не очень хорошо, было бы намного лучше, если бы вы объяснили, что он делает и как.
Петер - Восстановить Монику