![如何根据perl中的多个字段提取行](https://linux22.com/image/125661/%E5%A6%82%E4%BD%95%E6%A0%B9%E6%8D%AEperl%E4%B8%AD%E7%9A%84%E5%A4%9A%E4%B8%AA%E5%AD%97%E6%AE%B5%E6%8F%90%E5%8F%96%E8%A1%8C.png)
如何根据perl中的多个字段提取行
我有以下文件:file1.txt,我想根据多个字段的复合匹配提取行,这意味着如果该行仅包含所有这些字段的组合,则它应该提取包含这些字段的行
tcp
10.11.38.224
10.185.34.240
9012
文件1.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";
}
我编写了上面的脚本,它再次列出了匹配的行以及文件的全部内容
我的输出:
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
我什至在搜索时删除了双引号并尝试:
my @llll = grep {/$fld0/ && /$sIP/ && /$dIP/ && /$fld5} @gitLines_mst;
我收到错误:
Search pattern not terminated at ./sample line 11.
我想要的输出是:
access firewall tcp 10.11.38.224 255.233.212.111 10.185.34.240 244.255.240.211 eq 9012
答案1
#!/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))
}
(该if
语句可以全部写在一行上,但这样的格式更容易阅读)
将其保存到例如myscript.pl
,使用 使其可执行chmod +x myscript.pl
,并运行为:
$ ./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
不过,这个程序并不是很有用。它实际上只做一件事,打印与所有四个搜索条件完全匹配的行。
注意:作为一般规则,对于这样的程序,最好将它们编写为过滤器 - 即从标准输入和/或命令行上提到的任何文件名获取输入,而不是将特定文件名硬编码到程序中。
这样,它可以与任何文件名一起使用,或者从grep
或awk
或某些其他程序的输出获取输入。
Perl 中的文件<>
句柄正是这样做的。它将从标准输入获取输入和在命令行上作为参数给出的文件名(如果有)。
while (<>) { ...code... }
您会在 Perl 程序中经常看到它,这些程序对标准输入和/或文件输入进行搜索、重新格式化、提取数据以及执行其他操作。
根据昨天的类似问题,如果您想要具有有意义名称的变量而不仅仅是数组@F
,您可以这样写:
#!/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))
}
您可以将其用于undef
您不关心且不打算使用的任何字段。例如
my (undef, undef, $proto, $srcIP, undef, $destIP, undef, undef, $port) = split;
顺便说一句,这样的事情也可以很容易地完成awk
:
$ 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
或作为 perl 一行:
$ 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