I would like to retrieve information from Mac OSX's scutil
command with a perl script.
The output generated by that tool is somewhat similar to JSON, but so far I failed to find anything that is capable of parsing that.
Example:
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
}
}
I already managed to retrieve particular elements via regexps, but as I need to make several different lookups, I'm looking for a smarter, more generic approach.
Now, before I reinvent the wheel by coding yet-another-perl-parser, I hope that somebody recognizes this format and can give some advise how to parse this in - let's say - a nested perl hash map.
Any comments welcome.
In Perl, you can use Marpa::R2, a Perl interface to Marpa, a general BNF parser.
Here is a quick example:
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 } );
Output:
\[
'scutil',
'scutil',
'> open',
'> show',
[
'path',
'State:/Network/Service/0F70B221-EEF7-4ACC-96D8-ECBA3A15F132/IPv4'
],
'<dictionary>',
'{',
[
'pairs',
[
'pair',
[
'name',
'ARPResolvedHardwareAddress'
],
':',
[
'value',
[
'mac',
'00:1b:c0:4a:82:f9'
]
]
],
[
'pair',
[
'name',
'ARPResolvedIPAddress'
],
':',
[
'value',
[
'ip',
'10.10.0.254'
]
]
],
[
'pair',
[
'name',
'AdditionalRoutes'
],
':',
[
'value',
[
'array',
'<array>',
'{',
[
'items',
[
'item',
[
'index',
'0'
],
':',
[
'value',
[
'dict',
'<dictionary>',
'{',
[
'pairs',
[
'pair',
[
'name',
'DestinationAddress'
],
':',
[
'value',
[
'ip',
'10.10.0.146'
]
]
],
[
'pair',
[
'name',
'SubnetMask'
],
':',
[
'value',
[
'ip',
'255.255.255.255'
]
]
]
],
'}'
]
]
],
[
'item',
[
'index',
'1'
],
':',
[
'value',
[
'dict',
'<dictionary>',
'{',
[
'pairs',
[
'pair',
[
'name',
'DestinationAddress'
],
':',
[
'value',
[
'ip',
'169.254.0.0'
]
]
],
[
'pair',
[
'name',
'SubnetMask'
],
':',
[
'value',
[
'ip',
'255.255.0.0'
]
]
]
],
'}'
]
]
]
],
'}'
]
]
],
[
'pair',
[
'name',
'Addresses'
],
':',
[
'value',
[
'array',
'<array>',
'{',
[
'items',
[
'item',
[
'index',
'0'
],
':',
[
'value',
[
'ip',
'10.10.0.146'
]
]
]
],
'}'
]
]
],
[
'pair',
[
'name',
'ConfirmedInterfaceName'
],
':',
[
'value',
[
'interface',
'en0'
]
]
],
[
'pair',
[
'name',
'InterfaceName'
],
':',
[
'value',
[
'interface',
'en0'
]
]
],
[
'pair',
[
'name',
'NetworkSignature'
],
':',
[
'value',
[
'signature',
[
'signature_item',
[
'signature_item_name',
'IPv4.Router'
],
'=',
[
'signature_item_value',
[
'ip',
'10.10.0.254'
]
]
],
[
'signature_item',
[
'signature_item_name',
'IPv4.RouterHardwareAddress'
],
'=',
[
'signature_item_value',
[
'mac',
'00:1b:c0:4a:82:f9'
]
]
]
]
]
],
[
'pair',
[
'name',
'Router'
],
':',
[
'value',
[
'ip',
'10.10.0.254'
]
]
],
[
'pair',
[
'name',
'SubnetMasks'
],
':',
[
'value',
[
'array',
'<array>',
'{',
[
'items',
[
'item',
[
'index',
'0'
],
':',
[
'value',
[
'ip',
'255.255.255.0'
]
]
]
],
'}'
]
]
]
],
'}'
]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With