2

I have a list of over 200 bind extensions files with exact subdomain information.

An example schema looks like this.

# /named_ext/db.mysite.com
subdomain                    A       200.201.202.203

I need to replace the entire line to a set of three different lines, likes this.

subdomain                    A       200.201.202.204
subdomain                    A       200.201.202.205
subdomain                    A       200.201.202.206

Any idea how to perform such replace under all /named_ext/ files?

4
  • 1
    So would the search be for * A 200.201.202.203 - in other words, any subdomain name, but specific A and IP address, or is the subdomain the same in each file?
    – Paul
    Aug 13, 2012 at 7:14
  • the subdomain is the same in each file.
    – Martin
    Aug 13, 2012 at 7:28
  • 1
    Are the ips to be added always increments of the original ip or are they constant?
    – speakr
    Aug 13, 2012 at 7:51
  • they're constants.
    – Martin
    Aug 13, 2012 at 18:09

3 Answers 3

2

You can use the following perl script exchange_ips.pl to exchange the ip either by three constant ips (function exchange_const()) or by three incremental ips (function exchange_incr()). Just add a comment (#) in front of the function call at the end of the script that you don't need.

Note that one or more incremental ips will be incorrect if the original ip ends with 253 or higher.

The script modifies all lines starting with $domainname. If the domain name doesn't matter or if your files only contain lines for just one/the same domain, then set my $domainname = ".+";.

#!/usr/bin/perl

use strict;
use warnings;

my @data = <STDIN>;

my $domainname = "subdomain";
my $const_ip1 = "123.123.123.123";
my $const_ip2 = "124.124.124.124";
my $const_ip3 = "125.125.125.125";

my $pattern = qr/^($domainname\s+A\s+)([\d\.]+)/is;

sub exchange_const($) {
    my $dataref = shift;
    my $found = 0;
    foreach (@$dataref) {
        if ($_ =~ m/$pattern/) {
            unless ($found) {
                $found = 1;
                printf "%s%s\n%s%s\n%s%s\n", $1, $const_ip1, $1, $const_ip2, $1, $const_ip3;
            }
        } else {
            print $_;
        }
    }
}

sub exchange_incr($) {
    my $dataref = shift;
    my $found = 0;
    foreach (@$dataref) {
        if ($_ =~ m/$pattern/) {
            unless ($found) {
                $found = 1;
                my $const = $1;
                my @iparr = split /\./, $2;
                for (1 .. 3) {
                    $iparr[3]++;
                    printf "%s%s\n", $const, join ".", @iparr;
                }
            }
        } else {
            print $_;
        }
    }
}

# exchange ip with constant ips
exchange_const(\@data);

# exchange ip with incremental ips
exchange_incr(\@data);

Call the script like this:

perl exchange_ips.pl < your_file

Loop over all files (with backup):

for f in /named_ext/*; do rename s/$/.bak/ $f; perl exchange_ips.pl < $f.bak > $f; done

Example:

Sample file to modifiy:

# some foo
subdomain                       A       200.201.202.203
# duplicate
subdomain                       A       200.201.202.203
# some bar
otherdomain                     A       99.99.99.99
otherdomain                     A       1.1.1.1
# another duplicate
subdomain                       A       200.201.202.203

Output of exchange_const():

# some foo
subdomain                       A       123.123.123.123
subdomain                       A       124.124.124.124
subdomain                       A       125.125.125.125
# duplicate
# some bar
otherdomain                     A       99.99.99.99
otherdomain                     A       1.1.1.1
# another duplicate

Output of exchange_incr():

# some foo
subdomain                       A       200.201.202.204
subdomain                       A       200.201.202.205
subdomain                       A       200.201.202.206
# duplicate
# some bar
otherdomain                     A       99.99.99.99
otherdomain                     A       1.1.1.1
# another duplicate
3
  • Great, but the looping is not working for me. Doesn't seem to be creating the bak files.
    – Martin
    Aug 13, 2012 at 18:41
  • I see in some cases, the origin line is declared twice with same IP. Is there any way with regex to delete the second one to avoid duplicating the return and avoid getting 6 lines?
    – Martin
    Aug 13, 2012 at 18:48
  • @Martin You can try changing rename s/$/.bak/ $f; to mv $f $f.bak; in the loop if rename doesn't work. Also, I edited my answer/script to filter duplicates by just remembering a found line and ignoring subsequent matches.
    – speakr
    Aug 13, 2012 at 21:41
2

Small bash script

You can do this with a simple sed command over each file:

for f in ./named_ext/* ; do
    sed -r -i 's/subdomain[ ]+A[ ]+200.201.202.203/subdomain A 200.201.202.204\nsubdomain A 200.201.202.205\nsubdomain A 200.201.202.206/g' $f
done

Explanation

The for loop enumerates ./named_ext/* and runs the sed line using the file $f. The -r will extend the regular expressian and -i will edit the file in place.

The regular expression replaces

subdomain                    A       200.201.202.203

with any number of spaces by

subdomain A 200.201.202.204
subdomain A 200.201.202.205
subdomain A 200.201.202.206

If you want to retain spacing, you can add the spaces in the sed line.

1
  • 1
    +1 Finally a good solution with sed! ;)
    – speakr
    Aug 14, 2012 at 13:40
1
#!/bin/bash

tempFile=tempFile

for f in /named_ext/* ; do
    awk '
    BEGIN {FS = OFS = "."}

    /[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$/ {
        for (i=0; i<3; i++) {
            $4++
            print $0
        }
    }' $f > $tempFile
    mv $tempFile $f
done

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .