Inserting text into a file but searching for the place to put it!

Hi

I would love a bit of help with a problem im having with a script. I need to insert a line of text which is saved in a variable called $fwInsert into a file whos name is saved in a variable called $server but it needs to be in a certain order.

The file is a forward file for a network and it will look something like this:

;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
wibble                IN         A          192.189.1.42
tesmachineend    IN         A           192.189.1.255

I need to insert a machine into this file (i have the line of test like this in the variable $fwInsert as mentioned above) so I need to search through the file by ip address, find out where i'm supposed to put it and the paste it. I have tried grep but it error'd saying too many arguments and ive tried sed but it did nothing, no text was inserted but no error either which I suppose is an improvement.
Any help would be greatly appreciated.

Thanks

Katie

ps im using shell not korn :slight_smile:

I assume the example is 'before insert', please show us after a successful update and a sample insert string.

A successful insert would look like this:

;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
testmachine3      IN         A          192.189.1.3
wibble                IN         A          192.189.1.42
tesmachineend    IN         A           192.189.1.255

vi '+/192\.189\.1\.2' log_file << EOF
o$fwInsert^[:wq
EOF

where the ^[ is the ESC character, entered by typing CONTROL-V ESCAPE in vi insert mode.

Also. It may be tricky to add the backslashes between the IP numbers...
So, you could probably get away without using them... But the dot is a RE token.

maybe this might be a tad better:


vi +/" 192.189.1.2$" log_file << EOF
...

... or...

vi +/" $IP$" log_file << EOF
...

1 Like
sed '/wibble/ i testmachine3      IN         A          192.189.1.3' file name

. This search for wibble line and add your line before that ( i flag is for insert). I m not sure is this what u want?

Those are fab, thanks but my problem is that each file will have a different set of computers in it so i cant just search for the computer name. the file is sorted by ip address and thats what i need to search with. Any ideas?

I was thinking a while loop that starts from the ip address and takes one off each time and searches for it. If it doesnt find it at all then it inserts the file at the top?

wow. at this point, how about a simplied input/output that shows all of your test cases?
better yet, you could post what you've tried so far and show what it's missing.

I've cooked up a quick Perl script for this problem. Given a line that has an IP address, the script loops through the file, compares the IP addresses and plugs the input line wherever appropriate.

$
$
$
$ # show the content of the data file "f21"
$ cat -n f21
     1  ;zone file for test001.btcuk
     2  $TTL 2d
     3  @      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
     4                          2010092401            ;               serial number with no of editings
     5                          24h                       ;               refresh
     6                          5m                        ;               update entry
     7                          1w                        ;               expirary
     8                          2h )                      ;                minimum
     9                          NS        testserver.servers009.btcuk
    10  testmachine1      IN         A          192.189.1.1
    11  testmachine2      IN         A          192.189.1.2
    12  wibble            IN         A          192.189.1.42
    13  tesmachineend     IN         A          192.189.1.255
$
$
$ # show the content of the Perl script "insertline.pl"
$ # hopefully the script comments are descriptive enough
$ cat -n insertline.pl
     1  #!perl -w
     2  # Name:  insertline.pl
     3  # Desc:  Inserts a line in the data file depending upon the
     4  #        comparison of IP addresses. I've assumed that lines containing IP
     5  #        addresses are at the end of the file.
     6  # Usage: perl insertline.pl "$server" "$fwInsert"
     7  $file = $ARGV[0];                                 # read in the file name
     8  $input = $ARGV[1];                                # read in the input line
     9  $inserted = 0;                                    # assume it's not inserted yet
    10  @x = split/[ .]+/,$input;                         # split input line to capture IP in $x[3,4,5,6]
    11  open (F, $file) or die "Can't open $file: $!";    # open file
    12  while (<F>) {                                     # loop through it
    13    chomp($line = $_);                              # chomp newline
    14    $ln = $line;                                    # assign current line to temp variable
    15    $ln =~ s/^\s+//g; $ln =~ s/\s+$//g;             # trim spaces from temp variable
    16    @fields = split(/[ \t]+/, $ln);                 # split its fields and store in array @fields
    17    if ($#fields == 3 and                           # if count of fields is 4 and
    18        $fields[3] =~ /^\d+(.\d+){3}/ and           # if the last field is an IP address and
    19        not $inserted) {                            # if input line hasn't been inserted yet
    20      @y = split/\./,$fields[3];                    # then capture IP address of current line in @y
    21      if (($y[0] <=> $x[3] ||                       # compare IPs by logical disjunction
    22           $y[1] <=> $x[4] ||
    23           $y[2] <=> $x[5] ||
    24           $y[3] <=> $x[6]) > 0)                    # if file IP > input IP
    25      {
    26        print $input,"\n",$line,"\n";               # then print input IP followed by file IP
    27        $inserted = 1;                              # and set inserted flag to true (so no more inserts)
    28      } else {
    29        print $line,"\n";                           # otherwise just print the line from file that has IP
    30      }
    31    } else {
    32      print $line,"\n";                             # if no IP in current line, then just print it
    33    }
    34  }
    35  print $input,"\n" if not $inserted;               # if input IP hasn't been added yet then do it now
    36  close (F) or die "Can't close $file: $!";         # clean up after ourselves. Ciao!
$
$
$ # define the shell variables
$ server="f21"
$ fwInsert="testmachine3      IN         A          192.189.1.3"
$
$
$ # invoke the script passing the shell variables to it
$ perl insertline.pl "$server" "$fwInsert"
;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
testmachine3      IN         A          192.189.1.3
wibble            IN         A          192.189.1.42
tesmachineend     IN         A          192.189.1.255
$
$
$ # try the start boundary condition
$ fwInsert="testmachine3      IN         A          192.177.1.128"
$ perl insertline.pl "$server" "$fwInsert"
;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine3      IN         A          192.177.1.128
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
wibble            IN         A          192.189.1.42
tesmachineend     IN         A          192.189.1.255
$
$
$ # try the end boundary condition
$ fwInsert="testmachine3      IN         A          192.199.1.0"
$ perl insertline.pl "$server" "$fwInsert"
;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
wibble            IN         A          192.189.1.42
tesmachineend     IN         A          192.189.1.255
testmachine3      IN         A          192.199.1.0
$
$
$

HTH,
tyler_durden

1 Like

Where's that perl script? I would like to learn from your work!

Umm... where's that perl script ??
It's right there in my post - immediately below "cat -n insertline.pl" starting from line 1 and ending at line 36 !

tyler_durden

lulz. Sorry.

#!/usr/bin/env ruby 

require 'ipaddr'
def dec2ip(dec) return IPAddr.new(dec, Socket::AF_INET).to_s end
def ip2dec(ip) return IPAddr.new(ip).to_i end
file=ARGV[0]
insertline=ARGV[1]
data=File.read(file) # read the whole file
# store all ip address
sortedip=data.scan(/(\d+\.\d+\.\d+\.\d+)/).flatten.map {|x| ip2dec(x)}
# get the ip address to be inserted
insertip=ip2dec(insertline.scan(/\d+\.\d+\.\d+\.\d+/)[0])
sortedip<<insertip
sortedip.sort!
# get the ip before the one being inserted
beforeip=dec2ip(sortedip[sortedip.index(insertip)-1])
data.split("\n").each do |x|
  x="#{x}\n#{insertline}\n"  if x.match(beforeip)
  puts x
end

$ echo $insert
testmachine4 IN A 192.189.1.4

# ruby test.rb file "$insert"
;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
testmachine3      IN         A          192.189.1.3
testmachine4      IN         A          192.189.1.4
wibble                IN         A          192.189.1.42
tesmachineend    IN         A           192.189.1.255


$ insert="testmachine20      IN         A          192.190.1.5"
$ ruby test.rb file "$insert"
;zone file for test001.btcuk
$TTL 2d
@      IN     SOA    testserver.servers009.btcuk.    root.servers009.btcuk (
                        2010092401            ;               serial number with no of editings
                        24h                       ;               refresh
                        5m                        ;               update entry
                        1w                        ;               expirary
                        2h )                      ;                minimum
                        NS        testserver.servers009.btcuk
testmachine1      IN         A          192.189.1.1
testmachine2      IN         A          192.189.1.2
testmachine3      IN         A          192.189.1.3
wibble                IN         A          192.189.1.42
tesmachineend    IN         A           192.189.1.255
testmachine20      IN         A          192.190.1.5

1 Like

Hi

Thanks for this code, its brill. I would love to use durden_tyler s perl (always wanted to learn perl, not touched it before though)

One problem is that the IP address isnt always at the end of the line. Soemtimes there is a description at the end of the line like this:

testmachinedesc       IN        A      192.189.1.42 ; used for stuff

Also, i just tested this on the dev virtual machine I have because the test files dont have descriptions (hence the confusion, sorry!) and it just prints the input a couple of lines after the bottom of the file (or at least it looks like it does when you print out the file when you run the perl) but when you go into the file its not there O_O.

Thanks for your help!