Beefy Boxes and Bandwidth Generously Provided by pair Networks
Think about Loose Coupling
 
PerlMonks  

Command line options

by rpelak (Sexton)
on Nov 01, 2011 at 19:48 UTC ( #935197=perlquestion: print w/ replies, xml ) Need Help??
rpelak has asked for the wisdom of the Perl Monks concerning the following question:

So I have run into a situation several times, that the standard modules don't seem to support. And that makes me think maybe I am doing it wrong...
So I wanted to come here and ask... :)

I write scripts... in various languages... perl and tcl to name the major ones.
Those scripts usually have command line interfaces.

I often find myself wishing I could check if that value of an option post-parsing came from the user providing it on the command line, or was just the default.
Seems odd. But it's true.

here is one such general case.
I have an option, it has a default that "might work" for the user. The users of course can also give a value, and that should always be used. But I could also derive a value from the env that if it comes up with a value at all (doesn't always) would be better than the default, yet should still lose to a user given value.

So basically the order of preference is, user given, derived, default.

Most parsers will handle user given, and default, but don't provide a good way to know which was used for any specific option.

I can (and have on occasion) written my own command line parser, but such a simple thing as if an option was actually on the command line seems like it would be in the normal parsers, yet I don't see it, making me think it isn't normal to need it. And thus I might be off, or my need it just uncommon.

thoughts?

Comment on Command line options
Re: Command line options
by roboticus (Canon) on Nov 01, 2011 at 20:03 UTC

    rpelak:

    For the specific case you cited, you don't really need to know where the value comes from--you just want the "right" one to "win". I tend to do it by calculating the least interesting value first, then overwriting with the "better" values. In that way, I don't really care which value wins. I just know that the last (most important) one does. For example:

    use strict; use warnings; use Getopt::Long; # General default value my $foo = 'default'; # Let environment override the default if (defined $ENV{FUBAR}) { $foo = $ENV{FUBAR}; } # The command-line option overwrites if it exists GetOptions("foo=s"=>\$foo); print "The foo parameter is '$foo'\n";

    A few different usages gives:

    $ perl foo.pl The foo parameter is 'default' $ export FUBAR='Gragnar' $ perl foo.pl The foo parameter is 'Gragnar' $ perl foo.pl -foo=BARBAZ The foo parameter is 'BARBAZ' $

    This technique has its shortcomings, obviously, such as when (a) the computation is expensive or (b) has undesirable side effects.

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      Good points... I had to look back at some code to figure out why I had determined that wouldn't work...
      The derivations could also look at values of other options to do their deriving. And yeah, you can get in circles this way, but in many cases it is clean.
      And of course you could also want to only look at another options value as part of your derivation if the user actually gave that value, rather than if it was the default...
        Having "special interactions" among different options seems like a bad idea. If you actually have specific cases where the kinds of logic you describe seem necessary, there's probably a way to simplify the interface. If you're just imagining that such situations might arise, don't waste your time worrying about it, because if they do, there should be a way to simplify things.

        You write user manuals for these tools, right? If an accurate description of how the options work is too complicated, users are going to use it the wrong way and get results they don't want.

Re: Command line options
by mrstlee (Beadle) on Nov 01, 2011 at 20:34 UTC
    I usually do it the other way round:
    GetOptions(\%opts, 'opt1=s', 'opt2=i',...); $opts{'opt1'} ||= ($ENV{OPT1} || 'default');
    Naturally you would change the assignment above if, for example, 0, was a legal value for opt1, otherwise if the user puts in 0 then either the env var or 'default' will get used.
Re: Command line options
by choroba (Abbot) on Nov 02, 2011 at 17:24 UTC
    Then store the three types of values in different places.
    $super_options{platform}{user} = $option{platform}; $super_options{platform}{default} = 'whatever'; $super_options{platform}{env} = $ENV{PLATFORM};
    And write a sub to apply the logic.
      yes of course

      The real question here wasn't "how can I do this"...
      It's, I would think that wanting to know if a value came from a default or the user would be common, but doesn't seem to be in the normal command line parsers...
      Why?
      Is it bad form for some reason?
      or just not needed often enough to be worth putting in?

        I would think that wanting to know if a value came from a default or the user would be common, but doesn't seem to be in the normal command line parsers... Why?

        Because it's actually not common. You're talking about "accountability" (tracking the provenance) for the options used in a given run of a tool, but in the general case, when it comes to actually executing the operations that are selected by a given set of parameters, the origins of the parameters make no difference -- it only matters what their effective values are.

        No matter whether "-f foobar" was set explicitly by the user on the command line, or came from an environment variable, or was a default value, it's going to do the same thing. The behavior invoked by '-f foobar' might depend on other params, but again, it's a matter of what those other param values are, rather than how they got to be what they are.

        Obviously, precedence is important, and the normal approach is "env overrides default, argv overrides both"; the only other consideration is that the default case should be the most typical.

        If you have a pressing need for "accountability" -- that is, tracking and documenting the causality of param settings for each run of the program -- that's a separate matter, going beyond the scope of typical command-option parsing. Set up a HoH whose primary keys are the option flags or parameter names; for each of these, you'll want a sub-hash whose keys are, say, "value" and "source".

        You can still use one of the standard modules (Getopt::Long or Getopt::Std), and use one or the other sequences proposed in the other replies. As you copy the parameter values into the HoH, you also say where that value is coming from (argv, env or default).

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://935197]
Approved by ww
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (7)
As of 2014-12-28 21:07 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (182 votes), past polls