http://qs321.pair.com?node_id=893498


in reply to Dynamic option

I'm not exactly clear what you mean by "user input" since the entire command line is "user input" - do you mean that you have an option that can be assigned an arbitrary number of values?

If so, you can do something like this on the command line:

findfiles --input=data --input=modem --input=apps -des "finding files" + -r 1000

And in your getopt definition, you would add, "input=s@" instead of "input=s". Alternatively, you could allow your users to assign a comma delimited list (no internal spaces), like this:

findfiles --input=data,modem,apps -des "finding files" -r 1000

That would add an extra processing step: just in case someone used the first syntax (multiple options), you would concatenate the options with a comma to form one long comma delimited list. Then you would split the long list back into individual options. Like this (note: pseudocode - might have typos):

my @input = split(/,/, join(',', $options{input}))

If you've learned about Getopt::Long from reading code examples, you might want to take a look at the Getopt::Long documentation. It has a fair bit of discussion about how to have multi-valued options and some examples. Multivalued command line arguments have been supported by the version that ships with Perl since at least 5.8.8

Replies are listed 'Best First'.
Re^2: Dynamic option
by Anonymous Monk on Mar 16, 2011 at 05:58 UTC

    That's not what i need.Basically I need a way for option values to have options.Let me explain again with an example,in the below example the option is "input" and it's values are data,modem,apps but for these values I want to add options (-nd -na -nc)?Can someone pls advise how can I achieve that?

    EXAMPLE:- findfiles -input [-nd -na ] data [-nc -nd] modem apps -des "finding fi +les" -r 1000 Basically ,pseudco code of what I want to achieve is below.Really appr +eciate if someone can give me the perlversion of the code. for each "input option value(meaning for data,modem,apps)" { call function A if not exits nd call function B if not exits na call function C if not exists nc }

      It is hard to give an answer without knowing your validation logic needs, whether or not -nc/-nd can themselves have values and so on. I use Perl 5.8.8 and 5.10.0. Given the features available to me, I'd do one of the following:

      (a) No validation needed: I'd just define the whole lot (-nd, -na, -nc) as options. That way you can easily test for existence like you are doing in your sample code. Also you can easily assign values. Just because something is in the option list doesn't mean that the user has to enter it.

      (b) Validation needed. There are a couple possibilities here. I'm still guessing at what you want though because I'm not sure of the meaning of the intial -input [-nd -na]. Are those defaults? Also I don't know which sub-sub-options (nd/na) can be applied to more than one sub-option(data/modem/app). Nor do I know if na/nd can have values of their own.

      If I were to (a) want to set defaults for data/modem/app (b) distinguish between -nd for data vs. -nd for modem, I might do something like this:

      • treat -data, -modem, -apps as separate options rather than values of -input
      • make na, nc, nd values of -input, -data, etc.
      • during the option validation phase, check data/modem/apps. If they don't have a value, assign them the default value specified by the input option. If the do, scan the values to make sure they are legal.

      But I might do something entirely different if -na, -nc, -nd had values of their own. It just isn't possible to answer your question without knowing more. Command line options are data. Anything more complicated than a simple list needs to be understood and analyzed like a mini-data model. Structure of any data depends on its functional dependencies (how many values can an option have, what are its constraints, what are the interdependencies among options, and so on). The possibilities are quite broad which is why you aren't likely to find some out of the box solution except for the most simple cases.

      When you've written up your more detailed explanation of your validation logic, I'd recommend, you update your original post with a what you wrote above plus the new validation information. I'd recommend you reply to your own original post with a comment rather than this one. (Anonymous monks can't edit their posts). I think that would be better than a reply to this comment. That way people can see your needs without having to burrow down into replies of replies. You are liable to get more on target answers that way.

      In the future, also please consider posting questions as a named user. You can edit your posts that way. In general, the ideal solution when an initial post is unclear is to update the initial post, but that option isn't available to you as an anonymous poster.

      Update - changed recommendation - anonymous monks can't update posts.

        To explain again ,the ones in "[]" are optional sub-options(they may or may not present always) to the values of "input"option, data,modem,apps are values to option "input",they can also change.
        EXAMPLE:- findfiles -input [-nd -na ] data [-nc -nd] modem apps -des "finding fi +les" -r 1000 Basically ,pseudco code of what I want to achieve is below.Really appr +eciate if someone can give me the perlversion of the code. for each "input option value" { call function A if not exits nd call function B if not exits na call function C if not exists nc }

      using Getopt::Long, you *can* do this, but it's not going to be pretty as you're going to have to wedge your code into it. As some others have suggested, read the complete docs for Getopt::Long; there's a lot in there you probably don't know about.

      For each defined option, you can supply a reference. If it's a scalar, array or hash ref, it's used as the place to store the value(s) for that option, but if it's code, it gets run. Using that, you can insert your own code into the option processing and do whatever you need. At least I've been able to do anything I've needed.

      For example: (untested)

      my $opt = { grot => 'default for grot', }; my $action = 'default action'; GetOptions( $opt, 'action=s' => sub { my ($name, $value) = @_; $action = $value; }, 'thing=s' => sub { my ($name, $value) = @_; $opt->{$value} = $action; }, ) or die "can't parse command-line:";

      And then you can invoke it as:

      ./myscript --action frob --thing ant --thing bee --action foo --thing cat

      I'm sure it's not exactly what you wanted, but then I'm not sure what you wanted except that this seems relevant for you to build it.