Reputation: 33
I know how to extract a line by searching for a single string in a file inside perl script and below command worked perfectly fine which gave the lines having 255.255.255.255 in it.
my @newList = grep /255.255.255.255/, @File1;
However when I want to search for multiple strings(fields) in a file, grep command is not working
I have below file where if sourceipaddress, destipaddr and port number matches, it should extract the entire line and write into an array
gitFile:
access abc permit tcp sourceipaddress sourcesubnet destipaddr destsubnet eq portnumber
This is the way I have chosen to resolve the issue where I'm splitting based on the fields and searching for those fields in an array using grep but it does not seem to work (Tried 5 different ways which are commented below but none of the commands worked). I just want a way to search multiple strings(which includes ipaddress) in a line. Kindly help as I’m struggling with this as I’m new to perl.
my @columns = split(' ',$line);
my $fld0 = $columns[3];
my $fld3 = $columns[6];
my $fld5 = $columns[9];
#my @gitLines = grep {$_ =~ "$fld0" && $_ =~ "$sIP" && $_ =~ "$dIP" && $_ =~ "$fld5"} @gitFile;
#my @gitLines = @gitFile =~ /$fld0|$sIP|$dIP|$fld5/;
#my @gitLines = grep /$fld0/ && /$sIP/ && /$dIP/ &&/$fld5/,@gitFile;
#grep {$fld0} && {$sIP} && {$dIP} && {$fld5} @gitFile;
#my @gitLines = grep /255.255.255.255/ && /$fld0/, @File1;
I'm trying this in Linux GNU/Linux flavor
Upvotes: 0
Views: 2985
Reputation: 16
Basicaly, I believe you are trying to find more than 1 match in a line and you have got each line in an array called @gitFile
.
I am trying to do it in a simpler way as per my understanding.
$fld0 = 'pattern1';
$fld1 = 'pattern2';
foreach(@gitFile)
{
if(($_=~ m/$fld0/ && $_ =~ m/$fld1/))
{
push(@gitLines ,$_);
}
}
Upvotes: 0
Reputation: 66964
Without complete code it is not clear what is going on in your program. I infer by context that $line
has a template for a line so you extract patterns from it, and that @gitFile
has all lines from a file. Then among those lines you want to identify the ones that have all three patterns.
The first attempt should be written as
my @gitLines = grep { /$fld0/ && /$fld1/ && /$fld2/ } @gitFile;
While you may indeed pick your delimiters, for any other than //
there must be the m
, so you can have grep { m"$fld0" && .. }
(there is no value in explicit $_
as it only adds noise). But I find it only obscuring to use uncommon delimiters in this case.
The second attempt is wrong as you cannot match an array. Also, using the alternation |
would match even when only one pattern matches.
Another way is to form a regex to parse the line instead of matching separately on each field
my $re = join '.*?', map { quotemeta } (split ' ', $line)[3,6,9];
my @gitLines = grep { /$re/ } @gitFile;
Regex patterns should be built using qr
operator but for the simple .*?
pattern a string works.
Here the patterns need be present in a line in the exact order, unlike in the grep
above. A clear advantage is that it runs regex over the line once, while in grep
the engine starts three times.
Note that it is generally better to process files line-by-line, unless there are specific reasons to read the whole file ahead of time. For example
# $line contains patterns that must all match at indices 3,6,9
my $re = join '.*?', map { quotemeta } (split ' ', $line)[3,6,9];
my @gitLines;
open my $fh, '<', $git_file_name or die "Can't open $git_file_name: $!";
while (<$fh>) {
next if not /$re/;
push @gitLines, $_;
}
More than the efficiency this has the advantage of being more easily maintained.
Upvotes: 1