Take the 2-minute tour ×
Super User is a question and answer site for computer enthusiasts and power users. It's 100% free, no registration required.

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?

share|improve this question
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 '12 at 7:14
    
the subdomain is the same in each file. –  Martin Aug 13 '12 at 7:28
1  
Are the ips to be added always increments of the original ip or are they constant? –  speakr Aug 13 '12 at 7:51
    
they're constants. –  Martin Aug 13 '12 at 18:09
add comment

3 Answers

up vote 2 down vote accepted

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
share|improve this answer
    
Great, but the looping is not working for me. Doesn't seem to be creating the bak files. –  Martin Aug 13 '12 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 '12 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 '12 at 21:41
add comment

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.

share|improve this answer
1  
+1 Finally a good solution with sed! ;) –  speakr Aug 14 '12 at 13:40
add comment
#!/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
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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