Reputation: 37
I'm using cat to get content of the file, and then I use regex to get what I want. When I change order of if's in example i put PASSWORD as a second one, IP will be empty.
#!/usr/bin/perl
my $param = $ARGV[0];
my $IP;
my $PASSWORD;
my $MODEM;
my @cat = `cat file`;
foreach my $line (@cat){
if ($line =~ /$param/){
if ($line =~ /MODEM:(\w+)/g){ $MODEM = $1; }
if ($line =~ /IP:((\d{1,3}\.){3}\d{1,3})/g){ $IP = $1; }
if ($line =~ /PASSWORD:(.+)/g){ $PASSWORD = $1; }
print $MODEM;
print $IP;
print $PASSWORD;
}
}
The content of a file (data is changed to fake values) :
MODEM:SOMETHING ID:1000018 MAC:606060606060 ID2:123499 IP:1.1.1.1 PASSWORD:pass123
Expected result is:
SOMETHING1.1.1.1pass123
But when I change the line of code to this:
if ($line =~ /MODEM:(\w+)/g){ $MODEM = $1; }
if ($line =~ /PASSWORD:(.+)/g){ $PASSWORD = $1; }
if ($line =~ /IP:((\d{1,3}\.){3}\d{1,3})/g){ $IP = $1; }
the result is :
SOMETHINGpass123
i.e. the IP is empty. Can someone explain me why this is happening?
Upvotes: 2
Views: 257
Reputation: 6626
Edit: you probably don't really want to use 3 complicated regex to parse your file. See Stefan Becker's answer for a better way.
You need to remove the /g
modifier.
Successive matches against the same string with the /g
start from the end of the previous match. Have a look at the relevant paragraph in perlretut.
In your file, MODEM
comes first, then IP
, then PASSWORD
. Which means that after matching /PASSWORD:(.+)/g
, you can't match /IP/g
which comes before in your string.
/g
modifier is mostly useful when you want to do something like
while ($string =~ /.../g) { ... }
Or of course, in list context, to get all the matches:
@matches = $string =~ /.../g
In your case, you just want to get different matches one by one, so no need for /g
modifier.
Upvotes: 7
Reputation: 5952
Maybe not the answer you were looking for, but IMHO for your structured data a simpler approach than regex is possible:
<KEY>:<VALUE
, i.e. can be converted to a hash#!/usr/bin/perl
use warnings;
use strict;
while (<DATA>) {
chomp;
my %fields = map { split(/:/) } split(' ');
print "$fields{MODEM} $fields{IP} $fields{PASSWORD}\n"
}
exit 0;
__DATA__
MODEM:SOMETHING ID:1000018 MAC:606060606060 ID2:123499 IP:1.1.1.1 PASSWORD:pass123
Another alternative would be
my %fields = /(\S+):(\S+)/g;
Test run:
$ perl dummy.pl
SOMETHING 1.1.1.1 pass123
Upvotes: 7