tags:

views:

73

answers:

3

I used the following Perl syntax in order to replace strings or IP address in a file:

 OLD=aaa.bbb.ccc.ddd   (old IP address)
 NEW=yyy.zzz.www.qqq   (new IP address)

 export OLD
 export NEW

 perl  -pe 'next if /^ *#/; s/\Q$ENV{OLD }\E/$1$ENV{NEW }$2/' file

example of problem:

I want to change the IP address in file from 1.1.1.1 to 5.5.5.5

But I get the following:

more file (before change)

11.1.1.10 machine_moon1



more file (after change)

15.5.5.50 machine_moon1

According to "after change example) the IP "11.1.1.10" must to stay as it is , because I want to change only the 1.1.1.1 and not 11.1.1.10

I need help about my perl one line syntax:

How to change my perl syntax only according to the following rule:

  RULE: Not change the IP address if:left IP side or right IP side have number/s 

Example

 IP=1.1.1.1    
 IP=10.10.1.11
 IP=yyy.yyy.yyy.yyy

 [number]1.1.1.1[number]    - then not replace

 [number]10.10.1.11[number]    - then not replace

 [number]yyy.yyy.yyy.yyy[number]    - then not replace



Other cases:

  [any character beside number ]yyy.yyy.yyy.yyy[[any character beside number ]] - then replace
+1  A: 

You should use look-behind and look-ahead syntax, see a good article on perlmonks : http://www.perlmonks.org/?node_id=518444

sputnick
@sputnickRegards about the useful information
jon
A: 

It might be easier to write a short script to do this.

use strict;
use autodie;

my $old_ip = 10.1.1.1; # or $ENV{'OLD'}
my $new_ip = 50.5.5.5; # or $ENV{'NEW'}

open my $infh, '<', $ARGV[0];
open my $outfh, '>', $ARGV[1];
while ( my $line = <$infh> ) {
  chomp $line;
  my @elems = split '\s+', $line;
  next unless $elems[0] eq $old_ip;
  print $outfh $new_ip . join(" ", @elems[1..$#elems]) . "\n";
}
close $outfh;
close $infh;
CanSpice
hi CanSpice - my target is to fix my perl one line syntax to support my case
jon
any way I cant use your example because the perl syntax is part of my bash script
jon
@jon => you can always save the code to a file and call that file with perl from your script, some problems are best solved in long form
Eric Strom
OK I will do that on other cases but please see @Sir solution - his solution is what I need
jon
Usually when people need a one-liner it's to not have any extra files to distribute for their shell script, makefile, or whatever.
brian d foy
+2  A: 

Here's what you start with:

OLD=1.1.1.1
NEW=5.5.5.5

export OLD
export NEW

~/sandbox/$ cat file
1.1.1.10  machine1
11.1.1.10 machine2
11.1.1.1  machine3
1.1.1.1   machine4
A1.1.1.1  machine5
A1.1.1.1  machine6
1.1.1.1Z  machine7

If you anchor the patterns to only match on word boundaries or non-digits (see perlre), you should only match a complete IP address:

~/sandbox/$ perl -pe 'next if /^ *#/; s/(\b|\D)$ENV{OLD}(\b|\D)/$1$ENV{NEW}$2/' file
1.1.1.10  machine1
11.1.1.10 machine2
11.1.1.1  machine3
5.5.5.5   machine4
A5.5.5.5  machine5
A5.5.5.5Z machine6
5.5.5.5Z  machine7
Sir Robert
its not work if the right side or left side have non numbers for example : echo A1.1.1.1 | perl -pe 'next if /^ *#/; s/\b$ENV{OLD}\b/$ENV{NEW}/'
jon
Well, the OP didn't specify that, but is this version about what you're looking for? Notice I just changed the \D (non-digit) to a \b|\D (word-boundary-OR-non-digit) and did capturing with parens.
Sir Robert
YES now its OK , the "\D" enable to replace if it charecter
jon
@Sir very good - short and smart solution
jon
Thanks =) Years of hard time in the perl mines... ;)
Sir Robert
"." is a metacharacter. I would first do something like "my $re = qr/\b\Q$ENV{OLD}\E\b/;", then "s/$re/$ENV{NEW}/"
runrig