Burvil
Burvil

Reputation: 95

Multiline replace in perl with extended expressions not working

I'm trying to parse the following multiline string (starting with ) and comment it out.

    -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
<!-- A "Connector" using the shared thread pool-->

So I tried using the following:

perl -i.bak -pe 'BEGIN{undef $/;}
        s/
            \s+ #space at beginning of line
            (<Connector\s+ #connector
             port=\"8080\"\s+  #port
             protocol=\"HTTP\/1\.1\" #protocol
             \n  #newline
            \s+connectionTimeout=\"20000\"\n # space, connection timeout, then newline
            \s+redirectPort=\"8443\" #redirect port
            \/> # end of connector entry in file
            ) # end capture for $1
        /
            <!--$1-->
        /msx
    ' server.xml

diff server.xml server.xml.bak

But the diff output shows nothing. Any idea what I'm missing here?

Upvotes: 1

Views: 63

Answers (2)

lordadmira
lordadmira

Reputation: 1832

Don't use that BEGIN block. The normal way to slurp in a text file is to use the -0 switch. That sets the input record seperator to the null character. If there is any chance there are nulls in the file use -0777.

If you know precisely what the search text is, you don't need anything as complicated as you wrote. Perl has that use case covered. The \Q \E operator automatically quotes any possibly troublesome characters but still allows variable substitution to happen.
$foo = 'f.oo bar$'; print qr/\Q$foo\E/;
(?^:f\.oo\ bar\$)

$pattern = qr{\Q<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />\E};
$text =~ s/($pattern)/<!-- $1 -->/;

I see that you want to do it as a command line so it would be something like this.

perl -i.bak -lp0e '$pattern = qr{\Q<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />\E};
s/($pattern)/<!-- $1 -->/; ' FILE

The code you put will only execute once because there is only "one line" to the input.

If there is wiggle room in the amount of whitespace, you can do a dynamic substitution on the pattern itself.

$pattern = qq{\Q<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />\E};
# Translate runs of escaped whitspace into a single \s+
$pattern =~ s/(?:\\\s)+/\s+/g;
$text =~ s/($pattern)/<!-- $1 -->/;

HTH

Upvotes: 0

Burvil
Burvil

Reputation: 95

I think I figured it out.

perl -i.bak -pe 'BEGIN{undef $/;}
        s/
            --> #preceding line ends a comment, with newline at end
            \s+ #space at beginning of line
            (<Connector\s+ #connector
             port=\"8080\"\s+  #port
             protocol=\"HTTP\/1\.1\" #protocol
            \s+connectionTimeout=\"20000\" # space, connection timeout, then newline
            \s+redirectPort=\"8443\" #redirect port
            \s+   #space
            \/> # end of connector entry in file
            ) # end capture for $1
        /
            -->\n<!-- $1 -->
        /msx
    ' server.xml

diff server.xml server.xml.bak
~

Upvotes: 2

Related Questions