1

I am writing a script that can do something like:

script-name --resource1=xxx --resource2=xxx

But this can go up to 50+. Is there a way to make GetOpt accept dynamic option names?

gdanko
  • 1,922
  • 4
  • 20
  • 31
  • 1
    Do the options have to work this way? Things like `--resources=xxx,xxx` that work with one option are out of question? –  Jun 13 '11 at 14:46
  • No because it's pretty complicated. It's an enhanced check_http for nagios. --resource1='/foo' --resource1_hostheader='bar' --resource1_rc='200' and so forth. So currently, I put them into a hash for each; %resource_hash, %resource_hostheader_hash, etc. – gdanko Jun 13 '11 at 14:53
  • then, perhaps you'd want to store this information in one option, instead of several, and then use a repeated option, like: `--resource=/foo:bar:200 --resource=/foo2:bar2:300` etc.. – P Shved Jun 13 '11 at 14:54
  • Pavel, that is POSSIBLE for there are about 20 options for each resource and unless the user memorized the order, things could get chaotic. – gdanko Jun 13 '11 at 15:07

4 Answers4

1

Would it work with the same option name repeated?

For example: script-name --resource=xxx --resource=xxx

Kevin ORourke
  • 691
  • 9
  • 10
  • 1
    I don't think so. See the number of options available for each resource here: http://pastebin.gdanko.net/441 – gdanko Jun 13 '11 at 15:10
1

What about auto-generating the options list for Getopt::Long like example below? Since the list of options will be likely pretty long, using Getopt::ArgvFile allow you to supply configuration file with options instead of specifying them on command-line.

use Getopt::Long;
use Getopt::ArgvFile;
use Data::Dump;

my @n = (1 .. 10);    # how many resources allowed
my %opts = (
    port                  => ':i',
    http_version          => ':s',
    invert_string         => ':s',
    ssl                   => '',
    expect                => ':s',
    string                => ':s',
    post_data             => ':s',
    max_age               => ':i',
    content_type          => ':s',
    regex                 => ':s',
    eregi                 => ':s',
    invert_regex          => '',
    authorization         => ':s',
    useragent             => ':s',
    pagesize              => ':s',
    expected_content_type => ':s',
    verify_xml            => '',
    rc                    => ':i',
    hostheader            => ':s',
    cookie                => ':s',
    encoding              => ':s',
    max_redirects         => ':i',
    onredirect_follow     => ':i',
    yca_cert              => ':s',
);

my %args = ();
GetOptions(\%args,
    map {
        my $i = $_;
        ( "resource$i:s", map { "resource${i}_$_$opts{$_}" } keys %opts )
    } @n
) or die;

dd \%args;
bvr
  • 9,687
  • 22
  • 28
  • 1
    I don't think I'd bother generating `@n`. Just have a `$n` variable, and then you can generate the list `1 .. $n` anytime you need it, which probably won't be very often. – cjm Jun 13 '11 at 20:26
  • @cjm - good point, for this case it would be even more obvious. – bvr Jun 14 '11 at 05:18
1

Yes, as I just figured out how to do it myself as I wanted to accept a -# argument and Getopt::Long doesn't accept regex for an option name. So this is what I did:

use Getopt::Long qw(:config pass_through);

my $ret=GetOptions(
    \%gops,
    'lines|l',  # lines/records to display
    ... cut ...
    '<>' => \&filearg,          # Handle file names also attach current options
);

I then defined the filearg() function:

sub filearg {
    my $arg=shift;

    # First see if it is a number as in -20 as shortcut for -l 20
        if ($arg =~ /^--?(\d)+$/) {
        $gops{'lines'}=$1;
    } elsif (-f "$arg" && -r "$arg") {
        my %ops=%gops;
        $fops{$arg}=\%ops;
        push(@files, $arg);
    } else {
        push(@badargs, $arg);
    }
    return(undef);
}

So what is needed is the pass_through option, a check for what you want and setting those things when seen. Above I had undefined options passed to my function. I use this for file checks and for a special option -# where # is some integer. If it doesn't match I add to a badargs array, as doing this will not cause GetOptions to fail, so I have to check this array after the return from GetOptions to see if errors were seen. You can also have it end on option error by ending the callback function with die("!FINISH"); which will cause GetOptions to terminate the script.

What I use it for is the ability to have something like -20 FILE1 -30 FILE2, so options can be overridden for subsequent files. I see you being able to do something similar with a check for the first part of the option name and then the value. So if all of your options start with --resource then look for something like this in your function: /^--?(resource\w+)=(.*)$/ and then add into option array.

Anyway, hope this helps.

Dave
  • 11
  • 1
0

Another method to try would be to just use some sort of configuration file. It seems like this might be the easiest method to both write and parse, given that you plan on having a large amount of information.

Matthew
  • 444
  • 1
  • 3
  • 14