使用perl解析scutil输出

joe*_*rgd 7 regex macos perl parsing json

我想scutil用perl脚本从Mac OSX的命令中检索信息.

该工具生成的输出有点类似于JSON,但到目前为止,我找不到任何能够解析它的东西.

例:

scutil
> open
> show State:/Network/Service/0F70B221-EEF7-4ACC-96D8-ECBA3A15F132/IPv4
<dictionary> {
  ARPResolvedHardwareAddress : 00:1b:c0:4a:82:f9
  ARPResolvedIPAddress : 10.10.0.254
  AdditionalRoutes : <array> {
    0 : <dictionary> {
      DestinationAddress : 10.10.0.146
      SubnetMask : 255.255.255.255
    }
    1 : <dictionary> {
      DestinationAddress : 169.254.0.0
      SubnetMask : 255.255.0.0
    }
  }
  Addresses : <array> {
    0 : 10.10.0.146
  }
  ConfirmedInterfaceName : en0
  InterfaceName : en0
  NetworkSignature : IPv4.Router=10.10.0.254;IPv4.RouterHardwareAddress=00:1b:c0:4a:82:f9
  Router : 10.10.0.254
  SubnetMasks : <array> {
    0 : 255.255.255.0
  }
}
Run Code Online (Sandbox Code Playgroud)

我已经设法通过regexp检索特定元素,但由于我需要进行几个不同的查找,我正在寻找一种更智能,更通用的方法.

现在,在我通过编码另一个perl-parser来重新发明轮子之前,我希望有人能够识别这种格式并且可以给出一些建议如何解析这个 - 比方说 - 一个嵌套的perl哈希映射.

任何评论欢迎.

rns*_*rns 5

在Perl中,您可以使用Marpa :: R2,这是Marpa的Perl接口,后者是常规BNF解析器

这是一个简单的示例:

use 5.010;
use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Deepcopy = 1;

use Marpa::R2;

my $g = Marpa::R2::Scanless::G->new( { source => \(<<'END_OF_SOURCE'),
    :default ::= action => [ name, value]
    lexeme default = action => [ name, value] latm => 1

    scutil ::= 'scutil' '> open' '> show' path '<dictionary>' '{' pairs '}'
    path ~ [\w/:\-]+

    pairs ::= pair+
    pair ::= name ':' value
    name ~ [\w]+
    value ::= ip | mac | interface | signature | array | dict

    ip ~ octet '.' octet '.' octet '.' octet
    octet ~ [\d]+
    mac ~ [a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]
    interface ~ [\w]+

    signature ::= signature_item+ separator => [;]
    signature_item ::= signature_item_name '=' signature_item_value
    signature_item_name ~ [\w\.]+
    signature_item_value ::= ip | mac

    dict  ::= '<dictionary>' '{' pairs '}'
    array ::= '<array>' '{' items  '}'
    items ::= item+
    item ::= index ':' value
    index ~ [\d]+

    :discard ~ whitespace
    whitespace ~ [\s]+
END_OF_SOURCE
} );

my $input = <<EOI;
scutil
> open
> show State:/Network/Service/0F70B221-EEF7-4ACC-96D8-ECBA3A15F132/IPv4
<dictionary> {
  ARPResolvedHardwareAddress : 00:1b:c0:4a:82:f9
  ARPResolvedIPAddress : 10.10.0.254
  AdditionalRoutes : <array> {
    0 : <dictionary> {
      DestinationAddress : 10.10.0.146
      SubnetMask : 255.255.255.255
    }
    1 : <dictionary> {
      DestinationAddress : 169.254.0.0
      SubnetMask : 255.255.0.0
    }
  }
  Addresses : <array> {
    0 : 10.10.0.146
  }
  ConfirmedInterfaceName : en0
  InterfaceName : en0
  NetworkSignature : IPv4.Router=10.10.0.254;IPv4.RouterHardwareAddress=00:1b:c0:4a:82:f9
  Router : 10.10.0.254
  SubnetMasks : <array> {
    0 : 255.255.255.0
  }
}
EOI

say Dumper $g->parse( \$input, { trace_terminals => 0 } );
Run Code Online (Sandbox Code Playgroud)

输出:

use 5.010;
use strict;
use warnings;

use Data::Dumper;
$Data::Dumper::Indent = 1;
$Data::Dumper::Terse = 1;
$Data::Dumper::Deepcopy = 1;

use Marpa::R2;

my $g = Marpa::R2::Scanless::G->new( { source => \(<<'END_OF_SOURCE'),
    :default ::= action => [ name, value]
    lexeme default = action => [ name, value] latm => 1

    scutil ::= 'scutil' '> open' '> show' path '<dictionary>' '{' pairs '}'
    path ~ [\w/:\-]+

    pairs ::= pair+
    pair ::= name ':' value
    name ~ [\w]+
    value ::= ip | mac | interface | signature | array | dict

    ip ~ octet '.' octet '.' octet '.' octet
    octet ~ [\d]+
    mac ~ [a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]':'[a-z0-9][a-z0-9]
    interface ~ [\w]+

    signature ::= signature_item+ separator => [;]
    signature_item ::= signature_item_name '=' signature_item_value
    signature_item_name ~ [\w\.]+
    signature_item_value ::= ip | mac

    dict  ::= '<dictionary>' '{' pairs '}'
    array ::= '<array>' '{' items  '}'
    items ::= item+
    item ::= index ':' value
    index ~ [\d]+

    :discard ~ whitespace
    whitespace ~ [\s]+
END_OF_SOURCE
} );

my $input = <<EOI;
scutil
> open
> show State:/Network/Service/0F70B221-EEF7-4ACC-96D8-ECBA3A15F132/IPv4
<dictionary> {
  ARPResolvedHardwareAddress : 00:1b:c0:4a:82:f9
  ARPResolvedIPAddress : 10.10.0.254
  AdditionalRoutes : <array> {
    0 : <dictionary> {
      DestinationAddress : 10.10.0.146
      SubnetMask : 255.255.255.255
    }
    1 : <dictionary> {
      DestinationAddress : 169.254.0.0
      SubnetMask : 255.255.0.0
    }
  }
  Addresses : <array> {
    0 : 10.10.0.146
  }
  ConfirmedInterfaceName : en0
  InterfaceName : en0
  NetworkSignature : IPv4.Router=10.10.0.254;IPv4.RouterHardwareAddress=00:1b:c0:4a:82:f9
  Router : 10.10.0.254
  SubnetMasks : <array> {
    0 : 255.255.255.0
  }
}
EOI

say Dumper $g->parse( \$input, { trace_terminals => 0 } );
Run Code Online (Sandbox Code Playgroud)