ewhitt has asked for the wisdom of the Perl Monks concerning the following question:

I need to write a script to do the following, but can't think of where to start. I have an application that accepts CLI commands such as:
enable server hostname test enable server console-type type vt100 enable server account root authenticaion-type password "bubba"
When viewing the system configuration, it appears as:
server { hostname test; console-type { type vt100; } account root { authentication-type { password "bubba"; } } }
My script needs to be able to take the configuration and translate it back into CLI commands. Any suggestions on how I can approach this? Thanks in advance!

Replies are listed 'Best First'.
Re: Approach to remove brackets from config
by samtregar (Abbot) on Aug 20, 2008 at 17:52 UTC
    I would code it in two steps. First, write a parser which parses your (bizarre) config format into a Perl data structure. For you example you might attempt to produce something like:

    my %data = ( server => { "hostname" => "test". "console-type" => { "type" => "vt100", }, "account root" => { "authentication-type" => { "password" => q{"bubba"} } } );

    Second, write some Perl code that takes your parsed data-structure and outputs the CLI commands. Neither step is completely trivial, but they shouldn't be too hard for a competent programmer. If it were my job I think I'd do the first step with Parse::RecDescent, but if you've never used it before it's probably more trouble than it's worth. Give it a try and post again if you run into trouble.

    -sam

      If the syntax of the config file is fully represented in the example, a single regex substitution on each line could be enough. Something like:

      s/^\s*([\w-])\s*/"$1" => /

      Rule One: "Do not act incautiously when confronting a little bald wrinkly smiling man."

        That doesn't work. It's not too far off, but I think a real parser will be easier to write and more reliable.

        -sam

Re: Approach to remove brackets from config
by FunkyMonk (Bishop) on Aug 20, 2008 at 21:16 UTC
    Just as samtregar suggested, a two-pass approach seemed right to me too. First pass, parse(), parses the data into a hashref, and the second pass, get_command_args(), extracts the data from the hash ref to build the list of command arguments.

    Two recursive subroutines in one perl program. I think I've been doing too much emacs lisp :-)

    use strict; use warnings FATAL => 'all'; chomp (my @config = <DATA>); my $config = parse(); for my $server ( keys %$config ) { my @args = get_command_args( $config->{$server} ); print "enable $server $_\n" for @args; } sub get_command_args { my $cfg = shift; my @arg_list; for my $k ( keys %$cfg ) { my $v = $cfg->{$k}; my $args = "$k "; if ( ref $v ) { $args .= join " ", get_command_args( $v ); } else { $args .= "$v "; } push @arg_list, $args; } return @arg_list; } sub parse { my $hash; while ( my $line = shift @config ) { if ( $line =~ /(\S.*\S) \s* \{/x ) { # keywords + { my $k = $1; $hash->{$k} = parse(); } elsif ( $line =~ /(\S+) \s+ (\S+) \s* ; \s* $/x ) { # key valu +e; $hash->{$1} = $2; } elsif ( $line =~ /^ \s* } \s* $/x ) { # } return $hash; } else { die $line } # can't ha +ppen! } return $hash; } __DATA__ server { hostname test; console-type { type vt100; } account root { authentication-type { password "bubba"; } } }

    Output:

    enable server account root authentication-type password "bubba" enable server hostname test enable server console-type type vt100