Perl - 如何提取多行

时间:2017-04-26 16:01:52

标签: perl

我有一个这样格式的文本文件(它是思科防火墙配置文件):

object-group network group21
 network-object host 10.254.3.120
 network-object host 10.254.3.121
 network-object host 10.254.3.122
object-group network group456_local
 network-object host 192.168.150.63
 network-object host 192.168.150.64
 network-object host 192.168.150.76
object-group network group456_proxy
 network-object host 10.241.150.63
 network-object host 10.241.150.64
 network-object host 10.241.150.65
object-group network group154
 network-object host 10.9.11.45
 network-object host 10.9.11.10

注意:是的,网络对象组前面的文件中有空格。

使用Perl,如果它包含单词group456,如何从对象组中提取所有行?我要做的是搜索整个配置文件,如果有一个名为group456的单词,输出打印应该是:

object-group network group456_local
 network-object host 192.168.150.63
 network-object host 192.168.150.64
 network-object host 192.168.150.76
object-group network group456_proxy
 network-object host 10.241.150.63
 network-object host 10.241.150.64
 network-object host 10.241.150.65

提前感谢您的帮助。

3 个答案:

答案 0 :(得分:2)

对行进行分组而不将整个文件读入内存的通用方法:

my @buf;
while (1) {
   my $line = <>;
   if (!defined($line) || $line !~ /^ /) {
      if (@buf) {
         ...
      }

      last if !defined($line);

      @buf = ();
   }

   push @buf, $line;
}

在这种情况下,请用

替换缺失的部分
print @buf
   if $buf[0] =~ /^object-group\s+network\s+\w*group456/;

如果将整个文件读入内存,则更简单。

my $file = do { local $/; <> };

print
   for
      grep { /^object-group\s+network\s+\w*group456/ }
         split(/^(?! )/m, $file);

与前面的答案不同,这些方法不要求块一个接一个,并且不需要知道下一个块将是什么。

答案 1 :(得分:1)

一个简单的解决方案是使用..运算符来收集设置起点和终点之间的行(例如group2 .. group3 + 1)。必须进一步进一步确保抓住所有线路然后移除最后一条线路。此解决方案假定您要捕获的组始终按顺序排列。

#!perl

use strict;
use warnings;

while (readline(*DATA)) {
  next unless /group2\b/ .. /group4\b/;
  last if /group4/;
  print;
}

__DATA__
object-group network group1
 network-object host 10.254.3.120
 network-object host 10.254.3.121
 network-object host 10.254.3.122
object-group network group2
 network-object host 192.168.150.63
 network-object host 192.168.150.64
 network-object host 192.168.150.76
object-group network group3
 network-object host 10.241.150.63
 network-object host 10.241.150.64
object-group network group4
 network-object host 10.9.11.45
 network-object host 10.9.11.10

您可以在接受文本,起始组和结束组的子例程中对此进行概括。

答案 2 :(得分:1)

此解决方案使用功能但丑陋的状态标志技术

输入文件一次读取一行,如果遇到某行,变量$print(最初 false )设置为 true 以非空格字符开头,包含group456

只要$print true

,就会打印每一行

请注意use autodie无需检查open是否成功

use strict;
use warnings 'all';
use autodie;

use constant FILE => 'firewall.cfg';

open my $fh, '<', FILE;

my $print = 0;

while ( <$fh> ) {

    $print = /group456/ if /^\S/;

    print if $print;
}

输出

object-group network group456_local
 network-object host 192.168.150.63
 network-object host 192.168.150.64
 network-object host 192.168.150.76
object-group network group456_proxy
 network-object host 10.241.150.63
 network-object host 10.241.150.64
 network-object host 10.241.150.65