首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用perl解析数据-捕获一系列文本

用perl解析数据-捕获一系列文本
EN

Stack Overflow用户
提问于 2015-06-15 00:04:31
回答 3查看 226关注 0票数 1

我正在编写代码来解析我网络上的所有接口,寻找特定的配置。等。

数据如下:

代码语言:javascript
复制
Interface fa1
  mode access
  port-security
  mac-address sticky
!
interface fa2
  mode trunk
!

基本上从“^接口”开始,最后是"!“。

我现在的算法是“记录”我需要的数据。

代码语言:javascript
复制
foreach $line (@input) {
    if ( $line =~ m/^interface.+\d/ && $line !~ m/interface Embedded-Service-Engine|BRI|TenGigabitEthernet|vlan|Port-channel|ATM|loopback/i) {
        $record = 1;
    }

    #$int ne '' is to handle the rest of the file not in this format
    if( $line =~ m/!/ && $int ne '') {

        #save data in format 'interface fa2,mode trunk'
        #if the interface doesn't have port-security
        push(@intlist, join(','split("\r\n",$int))."\n") unless $int =~ m/port-security/;
        $record=0;
        $int='';
    }
    if ($record) {
         $int.=$line;
    }
 }

虽然这在我的例子中有效,但我想要一个简单的方法来实现它。我搜索了一下,发现你可以使用“.”关于正则表达式

它将我的代码转换为:

代码语言:javascript
复制
@input # contains the file
@interfaces = grep (/^interface.+\d/ .. /!/, @input);

这给了我所有的接口数据,问题是现在每一行都是@interfaces数组中的一个元素。然后,我如何将数据拆分,使/^interface.+\d/ .. /!/中的所有内容都成为这个数组中的一个元素,而不需要创建更多的for循环?

目标是将其简化为一个元素,这样我就可以扫描它的接口,我不想查看interface Embedded-Service-Engine|BRI|TenGigabit以及具有正确配置的接口。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2015-06-16 03:41:56

这是我的最后解决办法。在这种情况下,我将搜索所有端口安全性不等于1的开关端口,这只是一个例子,可以对任何配置进行切换。如果该配置实际应用于这些接口,我也会忽略某些接口。

代码语言:javascript
复制
#!/usr/bin/perl
$MDIR='/currentConfig';

#list of interfaces you don't want to see to filter output
@omit =(
'MANAGEMENT.PORT',
'sup.mgmt',
'Internal.EtherSwitch',
'Router',
'ip address \d',
'STRA'
);
#join with '|' to form the regex
$dontwant = join('|',@omit);

#search criteria
$search='switchport port-security maximum [^1]';

opendir(DIR,$MDIR) or die $!;
@dirContents=readdir DIR;close DIR;

foreach $file (@dirContents) {
        open(IN,$MDIR.'/'.$file) or die $!;
        #record seperator to !
        $/='!';
        my @inFile=<IN>; close IN;
        #since the record seperator has been changed, '^' won't match beginning of line
        my @ints = grep (/\ninterface/i,@inFile);
        #set record seperator back to normal
        $/="\n";
        foreach $int (@ints) {
                if ( $int =~ m/$search/i && $int !~ m/$dontwant/) {
                        push(@finalint,$int);
                }
        }
}
#just list the interfaces found, i'll use this to make it comma seperated
foreach $elem (@finalint) {
        print $elem;
}
票数 0
EN

Stack Overflow用户

发布于 2015-06-15 08:29:24

看看$/,因为我认为这会有帮助。它是记录分隔符--默认为\n

然后,可以将正则表达式应用到当前的“块”中,以提取所需的数据--默认情况下,正则表达式/捕获组应用于隐式变量$_

例如。

代码语言:javascript
复制
#!/usr/bin/perl
use strict;
use warnings;


local $/ = '!';

while ( <DATA> ) {
    my ( $interface ) = m/Interface (\w+)/i;
    next if $interface =~ m/Embedded-Service-Engine/;
    my ( $mode ) = m/mode (\w+)/;

    print "$interface $mode\n";

    print "---next record---\n";
}

__DATA__
Interface fa1
  mode access
  port-security
  mac-address sticky
!
interface fa2
  mode trunk
!

如果您需要将数据保存在其他用途(例如,“流程随走”不合适),那么该作业的工具就是散列。

您可以使用上面的内容--并使用您感兴趣的特定键填充散列--也可以使用地图的魔力来帮助您。

代码语言:javascript
复制
#!/usr/bin/perl
use strict;
use warnings;

use Data::Dumper;
local $/ = '!';

my %interfaces; 

while ( <DATA> ) {
    my ( $interface ) = m/Interface (\w+)/i; 
    next if $interface =~ m/Embedded-Service-Engine/;
    my %interface_values =  map { my ( $key, $value ) = split; $key, $value || 1 } grep { /\w/ } split ( "\n" );
    $interfaces{$interface} = \%interface_values;
}

print Dumper \%interfaces

__DATA__
Interface fa1
  mode access
  port-security
  mac-address sticky
!
interface fa2
  mode trunk
!

这条map线基本上是:

  • 拆分\n上的当前记录以获取每一行。
  • 筛选‘不是word’值(所以空行和!)
  • 在whitepace上拆分每一行,以获得一个键和值对。
  • 如果未定义值,则将其设置为1。(因此,在本例中,port-security )
  • 使用这些键值对填充散列。
  • 然后使用每个接口ID的散列更新%interfaces

给予类似于:

代码语言:javascript
复制
$VAR1 = {
          'fa1' => {
                     'port-security' => 1,
                     'mode' => 'access',
                     'Interface' => 'fa1',
                     'mac-address' => 'sticky'
                   },
          'fa2' => {
                     'mode' => 'trunk',
                     'interface' => 'fa2'
                   }
        };
票数 1
EN

Stack Overflow用户

发布于 2015-06-15 09:27:50

散列或hashref将是您可以使用的结果。此外,基于固定结构的读取记录可以使用匹配的正则表达式读取。就像这样:

代码语言:javascript
复制
#!/usr/bin/perl -w

use strict;
use Data::Dumper;

our %MATCH;
*MATCH = \%+;

# read file into variable
my ( $file, $data ) = ( 'interfaces.txt', undef );
open( my $fh, '<', $file ) or die "cannot open file $file";
{
    local $/;
    $data = <$fh>;
}
close($fh);
print Dumper $data;

my $regex = qr{
  (?sm)
  interface           [^\w\n]+
  (?<interface>       (\w[^\n]+))
                      [^\w]+
  mode                [^\w]+
  (?<mode>            (\w[^\n]+))
                      [^\w]+
  ((?<portsecurity>   port-security)
                      [^\w]+)?        # port-security is optional
  (mac-address        [^\w]+
  (?<macaddress>      (\w[^\n]+))
                      )?              # mac-address is optional
  [^!]*
  !
}x;

my $results = {};
while ( $data =~ m/$regex/g ) {
    my $interface = $MATCH{interface};
    $results->{$interface} = { mode => $MATCH{mode} ? $MATCH{mode} : '' };
    $results->{$interface}->{'port-security'} = 1
      if defined $MATCH{portsecurity};
    $results->{$interface}->{macaddress} = $MATCH{macaddress}
      if defined $MATCH{macaddress};
}
print Dumper $results;

您输入的结果是:

代码语言:javascript
复制
$VAR1 = {
          'fa1' => {
                     'macaddress' => 'sticky',
                     'mode' => 'access',
                     'port-security' => 1
                   },
          'fa2' => {
                     'mode' => 'trunk'
                   }
        };

有一个以接口名称作为键值的散列,使您有机会对所需的接口使用“grep”。

如果您的结构不是固定的--在字段模式、端口安全和mac地址中没有排序--那么您需要一次读取接口记录,然后对每个字段使用单独的regexes来分割字段。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30835808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档