I think you might have a couple problems in the "doReplace" sub, because of how you build the replacement regex:
my $regex = "s/$old/$new/g";
- If you put "\Q" and "\E" around "$old" in that regex, the periods in the IP addresses and host names will only match literal periods; as it is, they will match any character (e.g. "123.1.3" also matches 123.1[012]3)
- You also need to anchor that regex -- as it is, if $old is "box.my.dom", it matches "thisbox.my.dom" and "thatbox.my.dom"; the same applies to IP addresses, especially when doing your router files, where you change only the first three components -- if $opt_oldip is "123.123.123.4", your regex looks for any occurrence of "123.123.123", which would include "89.123.123.123"
On top of that, you're taking it for granted that the command line option strings really are valid IP addresses and host names, and you're putting them into a shell command that you then pass to a single-arg system() call. Personally, I'd feel better if these were checked first -- better still if you don't put the one-liner perl script on the command line at all.
In terms of simplifying things (while also fixing the problems above), you could consider something like this (untested):
#!/usr/bin/perl
use strict;
use Getopt::Long;
# ... define arrays of file names, then ...
my ( $opt_ip, $opt_host );
GetOptions( 'ip=s' => \$opt_ip, 'host=s' => \$opt_host );
my $Usage = "Usage: $0 [-ip old:new] [-host old:new]\n";
die $Usage unless ( $opt_ip =~ /\S:\S/ or $opt_host =~ /\S:\S/ );
my $ipreg = qr/\d{1,3}(?:\.\d{1,3}){3}/;
my $hostreg = qr/\w+(?:\.\w+){2,}/;
if ( $opt_ip ) {
$opt_ip =~ /($ipreg):($ipreg)/ or die "Bad value for -ip: $opt_ip\
+n $Usage";
my ( $old, $new ) = ( $1, $2 );
doReplace( $old, $new, 'IP', \@ipFiles );
s/.\d+$// for ( $old, $new );
doReplace( $old, $new, 'RTR', \@routerfiles ) if ( $old ne $new );
}
if ( $opt_host ) {
$opt_host =~ /($hostreg):($hostreg)/ or die "Bad value for -host:
+$opt_host\n $Usage";
my ( $old, $new ) = ( $1, $2 );
doReplace( $old, $new, 'HOST', \@hostFiles );
}
sub doReplace
{
my ( $old, $new, $typ, $files ) = @_;
open TMP,">/tmp/$typ-config-editor.$$.perl" or die "can't write sc
+ript file: $!"
print TMP "s{\\b\\Q$old\\E\\b}{$new}\n";
close TMP;
for my $f ( @$files ) {
my $cmd = "perl -i .bak.$$ -p /tmp/$typ-config-editor.$$.perl
+$f";
print "cmd: $cmd\n";
# system( $cmd ) or print "\t $f changed\n";
# (system returns exit status of $cmd: 0 for success)
}
}
That still has the potential for trouble when editing the router files, if they contain any full IP addresses where the latter three components might match the first three components of the "old" IP address. If that's really a risk, you'll need to write a special one-liner script just for them. | [reply] [Watch: Dir/Any] [d/l] [select] |
thanks for taking time correcting my code.
I was being lazy not to check the arguments because i am the only one use this. well. no excuse.
To the second suggestion(anchor one) you mentioned, i think a \b will do it. anchor requires the line start with that ip or hostname
>>better still if you don't put the one-liner perl script on the command line at all.
you put the regex in a seperate file then system calls it at once. that looks no much difference than directly calling it in the same perl script though.
| [reply] [Watch: Dir/Any] |
you put the regex in a seperate file then system calls it at once. that looks no much difference than directly calling it in the same perl script though.
The difference is that in my version, the command line passed to system() contains only things that are created by the script itself -- including the name of a file that stores a temporary perl script to be run -- so the shell launched by system() won't do anything unexpected. In your version, where the content of the temp. perl script is included in the command line, unexpected things in the script (e.g. shell metacharacters that were not properly escaped) could cause the system() call to do things that you don't want.
There might be a problem with the temp. perl script, and in my version, the perl job in the subshell would just exit with an error condition. In your version, the problem might be that some characters in the temp script are being interpreted by the shell.
Another way around this is to use a multi-arg system() call.
| [reply] [Watch: Dir/Any] |
please read man sys-unconfig and tell me, why your script is better? | [reply] [Watch: Dir/Any] [d/l] |
| [reply] [Watch: Dir/Any] |
AND it "Executes all system configuration applications."
so sys-unconfig erases all your system configuration and let you configure them after the reboot. it's what your script wants to be and more.
this is not intendet to be offense, but i just see no point in writing a script that does what you can do by only typing _one_ system command.
| [reply] [Watch: Dir/Any] |