Paul Pathiakis
Paul Pathiakis

Reputation: 1

POSIX sed replacement on multiline

I'm trying to get this to work and I'm at a loss now:

I have a named.conf file. In it, I have line pattern:

/*
        forwarders {
                127.0.0.1;
        };
*/

I would like to use sed to remove the beginning /* and ending */ and to replace 127.0.0.1; with 8.8.8.8; 8.8.4.4;

I don't care if I have to write out intermediate files on the way. In fact I do that on multiple iterations to see where things fail as my full script does that upon each substitution in the file to see where things might fail.

I was trying the simplest part of this. Detect the forwarders and feed the next line to see if the 127.0.0.1 existed and replace it.

sed -e '/forwarders/ 
n       
/'127.0.0.1;'/'8.8.8.8; 8.8.4.4;'/' named.conf.1 > named.conf.2

This is POSIX sed from BSD/MacOSX, not GNU sed with it's non-portable extensions.

I appreciate the help.

Upvotes: 0

Views: 301

Answers (2)

kdhp
kdhp

Reputation: 2116

It can be made into a substitution by consuming the entire comment, and substituting over multiple lines.

\|^/\*$| {
        :l
        N
        \|\*/$|!bl
        s|^/\*\(.*forwarders[[:space:]]*{[[:space:]]*\)127\.0\.0\.1\(.*\)\*/|\18.8.8.8; 8.8.4.4\2|
}

Note that embedded and quoted comments will break a simple parser, such as this, and if such robustness is needed a more powerful tool should be used.

Upvotes: 1

Ed Morton
Ed Morton

Reputation: 203368

sed is for simple susbtitutions on individual lines, that is all. For anything else you should be using awk. This will work in any awk:

$ cat tst.awk
$0 == "/*" { inCmt=1 }
inCmt { cmt = (inCmt++ > 1 ? cmt ORS : "") $0 }
$0 == "*/" {
    if (cmt ~ /forwarders/) {
        sub(/127\.0\.0\.1;/,"8.8.8.8; 8.8.4.4;",cmt)
        gsub(/^[^\n]+\n|\n[^\n]+$/,"",cmt)
    }
    $0 = cmt
    inCmt=0
}
!inCmt { print }

$ awk -f tst.awk file
        forwarders {
                8.8.8.8; 8.8.4.4;
        };

Upvotes: 1

Related Questions