Replacing IP's in ./etc/hosts

A

Alex

Hello,

I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically. I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

print "The current ip is: $ip\n";
print "The ip in /etc/hosts is: $ip_hostfile\n";

if ($ip eq $ip_hostfile)
{
print "The ip's are the same. No changes made.\n";
}
else
{
print "The ip's are different, writing new ip to
/etc/hosts\n";
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

while (<INPUT>)
{
s/$ip_hostfile/$ip/g;
print OUTPUT;
}

close(INPUT);
close(OUTPUT);
}

Obviously, I haven't gotten to the part where I actually replace the
newhosts file with the /etc/hosts file, because the replacement of the
$ip_hostfile with the $ip is not working. It creates the new file,
and populates it with the contents of the INPUT file, but the new ip
doesn't get placed in the newhosts file. The ip that needs to be
changed doesn't get changed, it stays the same value as in the INPUT
file. However, what I have found is that in this line:
s/$ip_hostfile/$ip/g, if I replace the variables with actual ip's,
then the script works fine...the values are switched like they are
supposed to. So the problem seems to be that the variables are not
working in that line for some reason. The variables are initializing
correctly, bacause the print statements correctly show the ip's. So,
any help would be much appreciated.

Thanks,
Alex
 
B

Bob Walton

Alex wrote:

....
I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically. I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

print "The current ip is: $ip\n";
print "The ip in /etc/hosts is: $ip_hostfile\n";

if ($ip eq $ip_hostfile)
{
print "The ip's are the same. No changes made.\n";
}
else
{
print "The ip's are different, writing new ip to
/etc/hosts\n";
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

while (<INPUT>)
{
s/$ip_hostfile/$ip/g;
print OUTPUT;
}

close(INPUT);
close(OUTPUT);
}

Obviously, I haven't gotten to the part where I actually replace the
newhosts file with the /etc/hosts file, because the replacement of the
$ip_hostfile with the $ip is not working. It creates the new file,
and populates it with the contents of the INPUT file, but the new ip
doesn't get placed in the newhosts file. The ip that needs to be
changed doesn't get changed, it stays the same value as in the INPUT
file. However, what I have found is that in this line:
s/$ip_hostfile/$ip/g, if I replace the variables with actual ip's,
then the script works fine...the values are switched like they are
supposed to. So the problem seems to be that the variables are not
working in that line for some reason. The variables are initializing
correctly, bacause the print statements correctly show the ip's. So,
any help would be much appreciated. ....
Alex

My recommendation: Check and see if $ip and/or $ip_hostfile have line
terminators included in their values. If they do, chomp them and try
that. You might also quote the metacharacters (.'s) which occur in your
IP addresses when using them as a regexp. The metacharacters won't stop
them from matching in this case, but it is general good practice.
Something like:

s/\Q$ip_hostfile/$ip/g;

Also, you might want to check around in some Unix newsgroups -- seems
like the /etc/hosts mechanism is pretty well dated, replaced by BIND or
something. Maybe you don't need to do what you are doing.
 
C

Charles DeRykus

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

chomp to remove line endings (perldoc -f chomp):

chomp( $var = `...` );
die "... failed: $?" unless $? == 0;
...
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

also recommend defensive checks for potential open errors:

open(... ) or die "can't open: $!";


HTH,
 
J

John W. Krahn

Alex said:
I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically.

Have you thought about running DNS?
I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

Ick.

#!/usr/bin/perl -w
use strict;
use Socket;

my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\S+)/;

my $ip_hostfile = do {
my @temp;
while ( @temp = gethostent ) { $temp[0] =~ /Morphine/ and last }
inet_ntoa $temp[-1];
};

print "The current ip is: $ip\n";
print "The ip in /etc/hosts is: $ip_hostfile\n";

if ($ip eq $ip_hostfile)
{
print "The ip's are the same. No changes made.\n";
}
else
{
print "The ip's are different, writing new ip to
/etc/hosts\n";
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

while (<INPUT>)
{
s/$ip_hostfile/$ip/g;
print OUTPUT;
}

close(INPUT);
close(OUTPUT);
}

if ( $ip eq $ip_hostfile ) {
print "The ip's are the same. No changes made.\n";
exit 0;
}

print "The ip's are different, writing new ip to /etc/hosts\n";

( $^I, @ARGV ) = ( '.back', '/etc/hosts' );

while ( <> ) {
s/^\Q$ip_hostfile\E\b/$ip/;
print;
}

__END__

Obviously, I haven't gotten to the part where I actually replace the
newhosts file with the /etc/hosts file, because the replacement of the
$ip_hostfile with the $ip is not working. It creates the new file,
and populates it with the contents of the INPUT file, but the new ip
doesn't get placed in the newhosts file. The ip that needs to be
changed doesn't get changed, it stays the same value as in the INPUT
file. However, what I have found is that in this line:
s/$ip_hostfile/$ip/g, if I replace the variables with actual ip's,
then the script works fine...the values are switched like they are
supposed to. So the problem seems to be that the variables are not
working in that line for some reason. The variables are initializing
correctly, bacause the print statements correctly show the ip's. So,
any help would be much appreciated.

First off, you don't need the /g modifier because you are only replacing
one thing and it has to be at the beginning of the line so you should
use ^ and contents of $ip_hostfile has dots which are special in regular
expressions so you have to quotemeta the variable and you should mark
the end of $ip_hostfile with \b so you get an exact match.


John
 
A

Alex

John W. Krahn said:
Alex said:
I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically.

Have you thought about running DNS?
I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

Ick.

#!/usr/bin/perl -w
use strict;
use Socket;

my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\S+)/;

my $ip_hostfile = do {
my @temp;
while ( @temp = gethostent ) { $temp[0] =~ /Morphine/ and last }
inet_ntoa $temp[-1];
};

print "The current ip is: $ip\n";
print "The ip in /etc/hosts is: $ip_hostfile\n";

if ($ip eq $ip_hostfile)
{
print "The ip's are the same. No changes made.\n";
}
else
{
print "The ip's are different, writing new ip to
/etc/hosts\n";
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

while (<INPUT>)
{
s/$ip_hostfile/$ip/g;
print OUTPUT;
}

close(INPUT);
close(OUTPUT);
}

if ( $ip eq $ip_hostfile ) {
print "The ip's are the same. No changes made.\n";
exit 0;
}

print "The ip's are different, writing new ip to /etc/hosts\n";

( $^I, @ARGV ) = ( '.back', '/etc/hosts' );

while ( <> ) {
s/^\Q$ip_hostfile\E\b/$ip/;
print;
}

__END__

Obviously, I haven't gotten to the part where I actually replace the
newhosts file with the /etc/hosts file, because the replacement of the
$ip_hostfile with the $ip is not working. It creates the new file,
and populates it with the contents of the INPUT file, but the new ip
doesn't get placed in the newhosts file. The ip that needs to be
changed doesn't get changed, it stays the same value as in the INPUT
file. However, what I have found is that in this line:
s/$ip_hostfile/$ip/g, if I replace the variables with actual ip's,
then the script works fine...the values are switched like they are
supposed to. So the problem seems to be that the variables are not
working in that line for some reason. The variables are initializing
correctly, bacause the print statements correctly show the ip's. So,
any help would be much appreciated.

First off, you don't need the /g modifier because you are only replacing
one thing and it has to be at the beginning of the line so you should
use ^ and contents of $ip_hostfile has dots which are special in regular
expressions so you have to quotemeta the variable and you should mark
the end of $ip_hostfile with \b so you get an exact match.


John


Thanks so much to everyone who so quickly came up with great
suggestions. I especially like the "Ick" comment. :) I can see that
I have a lot to learn about Perl.

Thanks again,

Alex
 
A

Alex

John W. Krahn said:
Alex said:
I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically.

Have you thought about running DNS?
I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

Ick.

#!/usr/bin/perl -w
use strict;
use Socket;

my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\S+)/;

my $ip_hostfile = do {
my @temp;
while ( @temp = gethostent ) { $temp[0] =~ /Morphine/ and last }
inet_ntoa $temp[-1];
};

print "The current ip is: $ip\n";
print "The ip in /etc/hosts is: $ip_hostfile\n";

if ($ip eq $ip_hostfile)
{
print "The ip's are the same. No changes made.\n";
}
else
{
print "The ip's are different, writing new ip to
/etc/hosts\n";
open(INPUT, "/etc/hosts");
open(OUTPUT, ">/etc/newhosts");

while (<INPUT>)
{
s/$ip_hostfile/$ip/g;
print OUTPUT;
}

close(INPUT);
close(OUTPUT);
}

if ( $ip eq $ip_hostfile ) {
print "The ip's are the same. No changes made.\n";
exit 0;
}

print "The ip's are different, writing new ip to /etc/hosts\n";

( $^I, @ARGV ) = ( '.back', '/etc/hosts' );

while ( <> ) {
s/^\Q$ip_hostfile\E\b/$ip/;
print;
}

__END__

Obviously, I haven't gotten to the part where I actually replace the
newhosts file with the /etc/hosts file, because the replacement of the
$ip_hostfile with the $ip is not working. It creates the new file,
and populates it with the contents of the INPUT file, but the new ip
doesn't get placed in the newhosts file. The ip that needs to be
changed doesn't get changed, it stays the same value as in the INPUT
file. However, what I have found is that in this line:
s/$ip_hostfile/$ip/g, if I replace the variables with actual ip's,
then the script works fine...the values are switched like they are
supposed to. So the problem seems to be that the variables are not
working in that line for some reason. The variables are initializing
correctly, bacause the print statements correctly show the ip's. So,
any help would be much appreciated.

First off, you don't need the /g modifier because you are only replacing
one thing and it has to be at the beginning of the line so you should
use ^ and contents of $ip_hostfile has dots which are special in regular
expressions so you have to quotemeta the variable and you should mark
the end of $ip_hostfile with \b so you get an exact match.


John

John,

I tried running your version of the script as:

#!/usr/bin/perl -w
use strict;
use Socket;

my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\S+)/;

my $ip_hostfile = do {
my @temp;
while ( @temp = gethostent ) { $temp[0] =~ /Morphine/ and last }
inet_ntoa $temp[-1];
};

if ( $ip eq $ip_hostfile ) {
print "The ip's are the same. No changes made.\n";
exit 0;
}

print "The ip's are different, writing new ip to /etc/hosts\n";

( $^I, @ARGV ) = ( '.back', '/etc/hosts' );

while ( <> ) {
s/^\Q$ip_hostfile\E\b/$ip/;
print;
}

And got the following errors:

Use of uninitialized value at ./ngscript line 13.
The ip's are different, writing new ip to /etc/hosts
Use of uninitialized value at ./ngscript line 23, <> chunk 5.

Any thoughts?

Thanks,
Alex
 
B

Brian Harnish

-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hello,

I have several Sun boxes that get their ip via DHCP. Once in a while,
when the ip's change, then I have to manually edit the /etc/hosts
files on all the boxes to correlate with the new IP. This is kind of
a hassle, so I wanted to use Perl to try and create a script that can
do this automatically. I am new to Perl, and scripting for that
matter, so I was hoping for some assistance. Here is what I have so
far for a machine named Morphine:

#!/usr/bin/perl -w

$ip = `ifconfig hme0 | grep inet | cut -f 2 -d " "`;

$ip_hostfile = `less /etc/hosts | grep Morphine | cut -f 1`;

#!/bin/sh
$ip = `whatever`
perl -wlpi -e "s/^\S+(.*\bMorphine\b)/$ip\$1/" /etc/hosts
# __END__

- Brian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.2 (GNU/Linux)

iD8DBQE/VMariK/rA3tCpFYRAnGDAJ9uFKylJjJnHD8NUzW+1u5UdZkgZQCdH5Rr
ZsbIrSBwpqFSU359wyzvbHQ=
=qDuf
-----END PGP SIGNATURE-----
 
J

John W. Krahn

Alex said:
I tried running your version of the script as:

#!/usr/bin/perl -w
use strict;
use Socket;

my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\S+)/;

my $ip_hostfile = do {
my @temp;
while ( @temp = gethostent ) { $temp[0] =~ /Morphine/ and last }
inet_ntoa $temp[-1];
};

if ( $ip eq $ip_hostfile ) {
print "The ip's are the same. No changes made.\n";
exit 0;
}

print "The ip's are different, writing new ip to /etc/hosts\n";

( $^I, @ARGV ) = ( '.back', '/etc/hosts' );

while ( <> ) {
s/^\Q$ip_hostfile\E\b/$ip/;
print;
}

And got the following errors:

Use of uninitialized value at ./ngscript line 13.
The ip's are different, writing new ip to /etc/hosts
Use of uninitialized value at ./ngscript line 23, <> chunk 5.

Any thoughts?

It looks like either $ip or $ip_hostfile contains the value undef. Is
the regular expression /inet addr:\s*(\S+)/ valid for your version of
ifconfig? Is the interface hme0 up and running? You should probably
put in some safety checks to ensure valid data before trying to change
/etc/hosts.


my ( $ip ) = `ifconfig hme0` =~ /inet addr:\s*(\d+\.\d+\.\d+\.\d+)/
or die "Invalid data from ifconfig hme0\n";


Also if /etc/hosts contains more than one line with the string
'Morphine' you may be changing the wrong line, for example:

0 # /etc/hosts file
1 # comment
2 #4.3.2.1 Morphine.org
3 5.4.3.2 one.Morphine.org Morphine1
4 5.4.3.3 two.Morphine.org Morphine

Line 2 will be skipped because it is a comment and line 3 will be
modified because it is the first host name that matches the regular
expression /Morphine/. If the string 'Morphine' only occures once in
the /etc/hosts file then you will change the correct entry otherwise you
may have to test for an exact match and you may want to test against the
alias field of gethostent() as well ($temp[1] in the code above.)



John
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,113
Latest member
Vinay KumarNevatia
Top