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

Hi, I am trying to parse some command line options of the form (using Getopt::Long):
-cmdline_option REG1=value1, value2, value3, value4 -cmdline_option REG2=value1, value2, value3, value4 ... -cmdline_option REG500=value1, value2, value3, value4 ...
and so on.
In the same program, I can parse another command line option of the form:
-cmdline_option_done REG1=Value -cmdline_option_done REG2=Value -cmdline_option_done REG3=Value ....
using the following format specifier in @opt_array
-cmdline_option_done=s%

For my present requirement, I need to be able to get a format specifier to accept not just a hash with key, value pairs as strings, but a hash format specifier where the key is a string, but the value is an array / array reference. Something like this:
my %opt = ( 'reg_ll_ul_pc_zp' => { REG1 => [0, 100, 100, 0], REG2 => [0, 100, 100, 0], REG3 => [0, 100, 100, 0], REG4 => [0, 100, 100, 0], REG5 => [0, 100, 100, 0], REG6 => [0, 100, 100, 0], }, ); my @opt_array = qw( reg_ll_ul_pc_zp=s???? ( :( ) ); GetOptions(\%opt, @opt_array);

Any help with tackling this issue would be greatly appreciated! Thanks in advance.

Replies are listed 'Best First'.
Re: Processing Complicated Command Line Options using Getopt
by JavaFan (Canon) on May 12, 2009 at 07:25 UTC
    It may help to say which of the many modules in the Getopt:: namespace you are trying to use.

    If you are trying it with Getopt::Long, it isn't going to work, unless you quote the command line arguments and do some postprocessing.

      Hi, Thanks for your reply.
      I was indeed trying it with Getopt::Long ;
      Do you suggest any other module which will help me avoid the post processing?
      Thanks once again.
Re: Processing Complicated Command Line Options using Getopt
by almut (Canon) on May 12, 2009 at 12:38 UTC
    ...where the key is a string, but the value is an array

    You could try something like this:

    #!/usr/bin/perl use strict; use warnings; use Getopt::Long; my $myopts = {}; my $curr_opt = ''; my $curr_key = ''; sub first_opt { $curr_opt = shift; $curr_key = shift; add_opt(shift); } sub add_opt { my $val = shift; $val =~ s/,$//; push @{$myopts->{$curr_opt}{$curr_key}}, $val; } # some commandline input { no warnings "qw"; @ARGV = qw( -cmdline_option1 REG1=value1, value2, value3, value4 -cmdline_option1 REG2=Value1, Value2, Value3, Value4 -cmdline_option2 REG1=val1, val2, val3, val4 -cmdline_option2 REG2=Val1, Val2, Val3, Val4 ); } GetOptions ( 'cmdline_option1=s%' => \&first_opt, 'cmdline_option2=s%' => \&first_opt, '<>' => \&add_opt, ); use Data::Dumper; print Dumper $myopts; __END__ $VAR1 = { 'cmdline_option2' => { 'REG1' => [ 'val1', 'val2', 'val3', 'val4' ], 'REG2' => [ 'Val1', 'Val2', 'Val3', 'Val4' ] }, 'cmdline_option1' => { 'REG1' => [ 'value1', 'value2', 'value3', 'value4' ], 'REG2' => [ 'Value1', 'Value2', 'Value3', 'Value4' ] } };
Re: Processing Complicated Command Line Options using Getopt
by ELISHEVA (Prior) on May 12, 2009 at 12:43 UTC

    Assuming that neither the properties (REG1, REG2, etc) nor the values assigned to them have meaningful embedded spaces and commas, this can be parsed with Getopt::Long.

    The "@{n,m}" spec syntax tells Getopt::Long to read multiple values after an option even without repeating the option flag, so you can use this spec to get gather together all the values that belong to the -cmdline_option flag. However, once you retrieve all the values for -cmdline_options you will only have an array of values. Getopt::Long doesn't know how to build HoA's for a single option flag so you will have to do it yourself, like this:

    use strict; use warnings; use Getopt::Long; # fake populate ARGV my $sLine= <<EOF; -cmdline_option REG1=value1.1, value1.2, value1.3, value1.4 -cmdline_option REG2=value2.1, value2.2, value2.3, value2.4 -cmdline_option REG3=value3.1, value3.2, value3.3, value3.4 EOF @ARGV = split(/\s+/, $sLine); sub makeKeyValuePairsIntoHoA; # ==================================================== # parse the command line # ==================================================== my @aCmdLineOpts; GetOptions('-cmdline_option=s@{0,}' => \@aCmdLineOpts); my $hCmdline = makeKeyValuePairsIntoHoA(\@aCmdLineOpts); # see results foreach my $k (sort keys %$hCmdline) { my $v = $hCmdline->{$k}; print "$k:<@$v>\n"; } # ==================================================== # subroutine for making key-value pairs into an HoA # ==================================================== sub makeKeyValuePairsIntoHoA { my ($aValues) = @_; # consolidate arguments so that all the # values belonging to REG1= are in a single # comma delimited list without spaces. my $sAllInOne = join(' ', @$aValues); $sAllInOne =~ s/\s*,\s*/,/g; # split into key-value pairs on whitespace my @aKeyValuePairs = split(/\s+/, $sAllInOne); my %hKeyValuePairs = map { my ($k,$v) = /(\w+)+=(.*)/; $k => [ split(/,/, $v) ] } @aKeyValuePairs; return \%hKeyValuePairs; }

    Best, beth

Re: Processing Complicated Command Line Options using Getopt
by leocharre (Priest) on May 12, 2009 at 13:31 UTC
    There's a possibility you're taking the wrong approach.

    Consider:

    1. Breaking up your cli into smaller pieces

      I.E. If your 'bin/cli' will clean the car if you pass it the --clean-car flag, consider moving that functionality to 'bin/clicleancar'

    2. Using a data file as input

      If this is a complex procedure, would it be useful to accept as input a YAML config file as option paramaters?

    Ultimately you're the judge of this.

    You may be in a situation a-la imagemagick, or mplayer .. these projects have already broken up their functionality into mplayer/mencoder/etc.. and convert/mogrify/etc. But the nature of the beast is such- that their cli is a monster.

Re: Processing Complicated Command Line Options using Getopt
by ganeshts (Initiate) on May 13, 2009 at 03:14 UTC
    Thanks to everyone who has chimed in to help me out with this issue.

    The nub of the issue, I gather, is that it is not possible to parse in an 'hash of arrays' using Getopt::Long directly.

    From the replies, I believe there are two possible solutions:
    1. Use a subroutine as the target of the command line option and do the parsing within that (as demonstrated by almut in his code example)
    2. Use a string array as the target of the command line option and do further post processing

    I dwelt upon this a bit, and with the helpful advice from JavaFan, I decided to use Getopt::Long with the s% specifier, such that the value parsed in from the options was a string (4 numbers separated by commas, within double quotes). Simple post processing was then applied and the values successfully placed into arrays for future use within the program.

    Once again, Thanks to everyone who spared their time and efforts to help me out.