Vibes
Vibes

Reputation: 33

How to search for multiple strings in same line using perl?

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

Answers (2)

livs
livs

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

zdim
zdim

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

Related Questions