1

How to extract a line based on the multiple fields in perl

I have below file: file1.txt and I want to extract line based on composite match of multiple fields meaning if the line has combination of all these fields only it should extract the line that contains those fields

tcp
10.11.38.224
10.185.34.240
9012

file1.txt

access firewall udp 10.14.90.111 240.230.111.222 10.13.45.21 255.255.230.240 eq 8443
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012
#!/usr/bin/perl

open(SOURCE,"<file1.txt");
while (my @gitLines_mst = <SOURCE>)
{
my $fld0 = "tcp";
my $sIP = "10.11.38.224";
my $dIP = "10.185.34.240";
my $fld5 = "9012";
print "$fld0";
my @llll = grep {"/$fld0/" && "/$sIP/" && "/$dIP/" && "/$fld5"} @gitLines_mst;
print "here please: @llll \n";
}

I wrote the above script, it is listing out matched line along with the entire contents of file again

my output:

access firewall udp 10.14.90.111 240.230.111.222 10.13.45.21 255.255.230.240 eq 8443
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

I even removed double quotes while searching and tried:

my @llll = grep {/$fld0/ && /$sIP/ && /$dIP/ && /$fld5} @gitLines_mst;

I got the error:

Search pattern not terminated at ./sample line 11.

My desired output is:

access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012
1
  • the 'search pattern not terminated' error is because there is no / after $fld5 on that line - i.e. the pattern isn't terminated, just as the error msg says. It should be /$fld5/.
    – cas
    Jan 16, 2018 at 7:26

1 Answer 1

2
#!/usr/bin/perl

while(<>) {
  @F = split;  # split input line into array @F using whitespace as separator.
  # Note: perl arrays start from 0, not 1.

  print if (($F[2] eq 'tcp') && 
            ($F[3] eq '10.11.38.224') &&
            ($F[5] eq '10.185.34.240') &&
            ($F[8] == 9012))
}

(that if statement could be all on one line but it's much easier to read formatted like this)

Save this to e.g. myscript.pl, make executable with chmod +x myscript.pl, and run as:

$ ./myscript.pl file1.txt 
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

This program isn't terribly useful, though. It really only does one thing, print lines exactly matching all four of the search criteria.

Note: as a general rule, for programs like this it is better to write them as a filter - i.e. to take input from stdin and/or any filenames mentioned on the command line than to hard-code a specific filename into the program.

That way, it can be used with any filename, or take input from grep or awk or some other program's output.

The <> file handle in perl does exactly that. It will take input from stdin AND filenames (if any) given as arguments on the command line. while (<>) { ...code... } is something you'll see a lot in perl programs that search, reformat, extract data from, and do other things to stdin and/or file input.


based on your similar question from yesterday, if you want variables with meaningful names rather than just an @F array, you could write it like this:

#!/usr/bin/perl

while(<>) {
  my ($access, $something, $proto, $srcIP, $srcmask,
      $destIP, $destmask, $eq, $port) = split;

  print if (($proto  eq 'tcp') && 
            ($srcIP  eq '10.11.38.224') &&
            ($destIP eq '10.185.34.240') &&
            ($port   == 9012))
}

and you can use undef for any fields you don't care about and don't intend to ever use. e.g.

  my (undef, undef, $proto, $srcIP, undef, $destIP, undef, undef, $port) = split;

BTW, something like this could be done fairly easily in awk too:

$ awk '$3=="tcp" && $4=="10.11.38.224" && $6=="10.185.34.240" && $9==9012' file1.txt 
access firewall 1 10.11.38.224 255.233.212.111 1 244.255.240.211 eq 9012

or as a perl one-liner:

$ perl -lane 'print if $F[2] eq "tcp" && $F[3] eq "10.11.38.224" && $F[5] eq "10.185.34.240" && $F[8] == 9012' file1.txt 
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .