【问题标题】:How to search for multiple strings in same line using perl?如何使用perl在同一行中搜索多个字符串?
【发布时间】:2018-01-16 21:47:22
【问题描述】:

我知道如何通过在 perl 脚本中的文件中搜索单个字符串来提取一行,并且下面的命令工作得非常好,它给出了包含 255.255.255.255 的行。

my @newList = grep /255.255.255.255/, @File1;

但是,当我想在一个文件中搜索多个字符串(字段)时,grep 命令不起作用

我有下面的文件,如果 sourceipaddress、destipaddr 和端口号匹配,它应该提取整行并写入数组

git文件:

access abc permit tcp sourceipaddress sourcesubnetdestipaddr destsubnet eq 端口号

这是我选择解决问题的方法,即我根据字段进行拆分并使用 grep 在数组中搜索这些字段,但它似乎不起作用(尝试了 5 种不同的方法,如下所述,但这些命令都不起作用)。我只是想要一种在一行中搜索多个字符串(包括 ipaddress)的方法。请帮助我,因为我是 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;

我正在 Linux GNU/Linux 风格中尝试这个

【问题讨论】:

  • @gitFile 中有什么内容?文件的所有行?
  • 如果我理解,您想提取文件中的所有 IP?这是对的吗?我们可以举一个输入的例子吗?
  • access-list firewall1 permit tcp 10.100.38.224 255.255.255.240 10.185.34.240 255.255.255.240 eq 9012...这就是内容的样子。我想根据第 3、4、6 和 9 个字段进行搜索并提取具有此组合的行
  • 请:编辑问题并进行澄清。很多东西都不太清楚。 (顺便说一句,您的示例显示了第 3、第 6 和第 9 个字段——没有您在评论中提到的第 4 个字段?)
  • 为了回答这个问题,我们需要一些示例数据和所需的输出。没有它,我们无法猜测到底发生了什么。请edit您的问题包括这些内容。

标签: perl


【解决方案1】:

如果没有完整的代码,就不清楚程序中发生了什么。我通过上下文推断$line 有一个行模板,因此您可以从中提取模式,并且@gitFile 具有文件中的所有行。然后,在这些行中,您要确定具有所有三种模式的行。

  • 第一次尝试应该写成

    my @gitLines = grep { /$fld0/ && /$fld1/ && /$fld2/ } @gitFile;
    

    虽然您确实可以选择分隔符,但对于 // 以外的任何分隔符,都必须有 m,因此您可以使用 grep { m"$fld0" && .. }(显式 $_ 没有任何价值,因为它只会增加噪音)。但我发现在这种情况下使用不常见的分隔符只会让人难以理解。

  • 第二次尝试是错误的,因为您无法匹配数组。此外,即使只有一个模式匹配,使用替换 | 也会匹配。

  • 另一种方法是形成一个正则表达式来解析行而不是在每个字段上单独匹配

    my $re = join '.*?', map { quotemeta } (split ' ', $line)[3,6,9];
    my @gitLines = grep { /$re/ } @gitFile;
    

    应该使用qr operator 构建正则表达式模式,但对于简单的.*? 模式,字符串可以工作。

    这里的模式需要以确切的顺序出现在一行中,这与上面的grep 不同。一个明显的优势是它在线路上运行一次正则表达式,而在grep 中,引擎启动了三次。

请注意,通常最好逐行处理文件,除非有特殊原因需要提前读取整个文件。例如

# $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, $_;
}

除了效率之外,这还具有更易于维护的优势。

【讨论】:

    【解决方案2】:

    基本上,我相信您正在尝试在一行中查找多个匹配项,并且您将每一行都放在一个名为 @gitFile 的数组中。

    根据我的理解,我正在尝试以更简单的方式进行操作。

    $fld0 = 'pattern1';
    $fld1 = 'pattern2';
    
    foreach(@gitFile)
    {
         if(($_=~ m/$fld0/ && $_ =~ m/$fld1/))  
         { 
             push(@gitLines ,$_);
         }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-03
      • 1970-01-01
      • 1970-01-01
      • 2012-05-26
      • 2012-03-13
      • 2020-06-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多