Beefy Boxes and Bandwidth Generously Provided by pair Networks
laziness, impatience, and hubris

better cli processing

by AlCapone (Novice)
on Nov 02, 2002 at 09:38 UTC ( #209935=perlquestion: print w/replies, xml ) Need Help??
AlCapone has asked for the wisdom of the Perl Monks concerning the following question:

Greetings fellow perl programmers. I'm new to this monastery, so go easy on me if I do something wrong. Here's the question: I'm writing a script which will require quite a lot of user input, which I'm going to take from @ARGV. Now, most of input is optional and naturally it can be random order with switches (-f file -s size -t time etc). Having a bunch of if statements with foreach() doesn't sounds like a great plan to me. So what do you guys use when want to get heaps of info from command line but don't want to have megabytes of if()'s? /me off to look at some pre-written perl files to see what they do...

Replies are listed 'Best First'.
Re: better Comand line argument processing
by SparkeyG (Curate) on Nov 02, 2002 at 09:50 UTC
    You may want to take a look at Getopt::Long and Getopt::Std. These modules come with perl, and should make the parsing of your command line arguments a snap.
      Hey Thanks Sparkey! I'm all over it - it looks just what I need. Thanks again.
Re: better cli processing
by chicks (Scribe) on Nov 02, 2002 at 14:07 UTC
    The Getopt:: stuff is ok, but I prefer AppConfig since it works with arguments from config files and the command line.
Re: better cli processing
by flarg (Initiate) on Nov 02, 2002 at 15:52 UTC
    On a related note, the Getopt::Long node says I can specify an option like 'foo --size=24' like this:

    >>> GetOptions("size i" => \$offset); <<<

    How can I use this feature to specify an option that may look like either of these:

    foo --size 24 --verbose --debug

    or a more compact version

    -vds 24

    I can't quite figure it out. The documentation contains alot of examples using references, and I references are a little beyond me right now (but I'm learning!).

      A couple of things you will want to read up on.

      First, you should look into storing the options in a hash, instead of passing a reference to a variable for each one. It's much easier. See Storing options in a hash for info on that.

      Second is aliases, or Options_with_multiple_names. Pretty straight-forward.

      Last, you want to look into Bundling for info on allowing the -vds 24 form.

      And here's some example code!

      #!/usr/bin/perl use warnings; use strict; use Getopt::Long; Getopt::Long::Configure('bundling'); our %Options; GetOptions(\%Options, 'size|s=i', # The | separates aliases, ie: s == size 'verbose|v', # What comes before the | is the name, which 'debug|d', # determines what hash entry (or variable) is +set. ); print "Debug mode\n" if $Options{debug}; print "Verbose mode\n" if $Options{verbose}; print "Size is: `$Options{size}'\n" if exists $Options{size}; print "Done.\n";

      This will take --verbose --size=24, or --size 24 -vd, or -vds24, or just about any other combination thereof. :)

      Black flowers blossum
      Fearless on my breath

        Beautiful. That's exactly what I was looking for. Thanks all!
      It's not possible with Getopt::Long. You can only use long options with that, and you can only use short options with Getopt::Std. What you want to do requires Getopt::Mixed.

      Makeshifts last the longest.

        Actually, I believe it is possible with Getopt::Long. Take a look at the bundling option.

        Update: Oh, and of course it helps to use the 'name|n' for defining the short form, since it's not done automatically. :)

        Black flowers blossum
        Fearless on my breath

Re: better cli processing
by BrowserUk (Pope) on Nov 02, 2002 at 22:25 UTC

    It may be worth pointing out that if you can live with putting = signs between your switches and their values:

    script -f=file -s=size -t=time

    instead if what you showed, you don't need to use a module or do any parsing yourself. Perl has this functionality built-in. Just add -s to your shebang under *nix or to the ftype definition under win32 and Perl will parse the values for you.

    It has its limitations, but also its benefits, and its as cheap as it gets.

    See perlrun for details.

    Nah! Your thinking of Simon Templar, originally played by Roger Moore and later by Ian Ogilvy
      ok, I have this
      #!/usr/bin/perl -s print $xyz if $xyz;
      which is shameless cut'n'paste from perldoc perlrun. Now, I'd *think* it works, but it doesn't. I dont get nothing whatsoever, no matter if I pass -xyz=abc or leave it out. The Almighty Manual Book says:

      The following program prints "1" if the program is invoked with a -xyz switch, and "abc" if it is invoked with -xyz=abc.

      But it doesn't. I tried on freebsd 4.4, linux 2.4.18. I even tested on winxp and nothing. And hey, if it doesn't work on _windows_ there have got to be something wrong with it! ;p

        Update2: I just noticed that you aren't printing a newline ("\n" or $/ (by default)) on the end of your print line. Is it possible that the line is getting buffered and not output somehow?

        Using this code

        #!perl -sw print $xyz,$/ if $xyz; __END__


        C:\test>210020 -xyz 1 C:\test>210020 -xyz=fred fred C:\test>

        This is on NT4/AS. NOTE though, the shebang line in my code is advisory only. The actual work being done by the ftype definition which I have set up like this

        C:\test>assoc .pl .pl=perl_script C:\test>ftype perl_script perl_script=e:\perl\bin\perl.exe -sw "%1" %* C:\test>

        I haven't used Perl under linux so I'm only guessing here. Have you tried doing

        /usr/bin/perl -s yourscript -xyz on your shell command line?

        I'm speculating that your shell is not respecting options supplied on the shebang line.

        There is more to this as well, once you get this to work in your environment(s), but the rest of this post is irrelevant if you can't get your test script to run.

        If you want to use -s in conjunction with strict, you need to take some extra step as the variables set my -s are globals which aren't use strict; complient.

        The fix is to this is to use vars qw/$xyz $file/; I'll dig out a short script showing you how I use the -s. Not that I necessarially do it correctly, but it works for me:)

        Update: Added a better example of using -s

        Nah! Your thinking of Simon Templar, originally played by Roger Moore and later by Ian Ogilvy

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://209935]
Approved by davis
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others wandering the Monastery: (4)
As of 2018-07-18 09:07 GMT
Find Nodes?
    Voting Booth?
    It has been suggested to rename Perl 6 in order to boost its marketing potential. Which name would you prefer?

    Results (388 votes). Check out past polls.