8

I am trying to find these three lines:

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

and replace them with:

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

When I try

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

It doesn't find it, I also tried to put \n in it, but it still didn't work:

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

These don't throw any errors it just doesn't uncomment the line. Any advice would help thanks!

5

sed reads each line in turn, so it'll never match a multiline pattern unless you nudge it in the right direction. The N command reads one line from the input and appends it to the pattern space.

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

Arguably, if you need a command other than s, then you should switch away from sed and to awk or perl. Here's a slightly more flexible Perl snippet that copes with multiline comments in a more general way.

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

Sed works on a line-by-line basis. It can be made to work on multiple lines, but it wasn't designed that way - and in my opinion it definitely shows when you attempt to use like that. But if you decide to go that way you will probably have to use registers. Check some of the solutions to https://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n to see how it can be done.

I prefer to use perl instead of sed for this kind of task (multi-line-oriented, I mean). The boilerplate you have to add before the search-and-replace (BEGIN...) is not obvious, but the regex seems cleaner to me:

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

Or, using grouping to shorten the expression and to allow you to use a regex there:

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

It should work both on occurrences with and without newlines between the comment markers and the code to be uncommented.

Adapted from:

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

  • Thank you for your help, looks like it's a pain, I decided to use a workaround – Doug Molineux May 20 '11 at 19:45
2

Here's a description of the multiline commands in SED: http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

It's a pain in the butt. You may want to follow Eduardo's advice and use perl -i -p -e instead.

  • I wouldn't link to unauthorized copies of copyrighted material. – Mark Wagner May 20 '11 at 19:58
1
  • /<\!--/ : matching string
  • :X : this is a label for branch command "b"
  • /-->/ : matching string
  • s@...@...@p : strip "<!--" , "-->" and print result
  • d : delete pattern space and start new cycle
  • N : if not match with /-->/ then append a line
  • bX : branch to :X label
  • p : just print a string that is not match with /<!--/

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'
  • 1) Thank you for your answer. 2) Inserting only code snippets is not really okay, it would be much better if you would explain, what it does and how. – peterh Jan 15 '17 at 5:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.