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

Hi, I'm a newcomer to Linux/Perl scripting, and I have a question - how do I effectively use flags in my Perl scripts?

For example, let's say I have a scripts that outputs the standard deviation of a list of numbers - I want to extend the functionality of this by adding a flag -m, causing the script to additionally output the mean of the data as well.

Here's what happens normally when run on a command line:

./stdev.pl 3 7 7 19 6

What I want is for it to work like so:

./stdev.pl -m 3 7 7 19 6, mean 9

How would I allow my script to detect such a flag?

Thanks!
-Jordan

Replies are listed 'Best First'.
Re: Usage of flags in scripts
by Lawliet (Curate) on Dec 31, 2008 at 23:06 UTC

    Well, I believe everyone will recommend you use a module to do this. I suggest using either getopt::long or getopt::simple.

    #!/usr/bin/perl use warnings; use strict; use Getopt::Long; use 5.010; # Just to use say() my ($mean, $sum); my $result = GetOptions ("mean" => \$mean); my @nums = @ARGV; foreach (@nums) { say; # Only calculate the mean if flag exists if ($mean) { $sum += $_; } } say $sum/@nums if $mean; __END__ $ perl mean.pl 1 3 2 1 3 2 $ perl mean.pl -m 1 3 2 1 3 2 2 $ perl mean.pl -mean 1 3 2 1 3 2 2

    Notice how Getopt::Long allows the user to type just enough of the switch to trigger it. If there was another switch called meek, the user would have to distinguish which switch they were triggering by typing either -mee (or -meek) or -mea (or -mean).

    Updated with example.

    And you didn't even know bears could type.

      Or you could-

      #!/usr/bin/perl -l

      -instead of-

      use 5.010; # Just to use say()

      To get print to act like say which is a bit more on point for the OP. :)

        or even...
        sub say { # Perl Hacks #86 print @_, "\n"; }

        Haha, that is neat. I need to reread perlrun more often ;)

        And you didn't even know bears could type.

      Great, thank you! One more question, though - is there a way I can stop Getopt::Long from parsing negative number arguments as flags?
      For example, if my data set is (12, 5, 7, 1, -3), -3 is parsed as as a flag, not a numerical argument

        After reading the documentation, I believe this can be done by changing use Getopt::Long; to use Getopt::Long qw(:config require_order);.

        require_order

        Whether command line arguments are allowed to be mixed with options. Default is disabled unless environment variable POSIXLY_CORRECT has been set, in which case require_order is enabled.

        See also permute, which is the opposite of require_order.

        Getopt::Long will stop processing flags and such once it sees an argument without a dash.

        And you didn't even know bears could type.

        These various getopt things parse tokens on the command line.

        In your case, perhaps Getopt::Std will be just fine. This not to say that that other suggestions aren't fine also.

        use Getopt::Std; my %opts; die "Usage $0 -m or -M #1 #2 #3..." if (!getopts( "mM", \%opts) || @ARGV !=0 || keys %opts != 2); CalculateMean() if $opts{m}; #@ARGV has just #1 #2 #3 ...now. CalculateMedian() if $opts{M};

        getopts::Std take a string and a ref to a hash as args. The magic of getopts in its various flavors is that it removes the option and the parameter (if any) from @ARGV.

        There is a syntax for this: "mf:" means that "-m" doesn't have an arg, but that "-f" does, like someprogram -m -f filename 1 2 3. In this case the %opts hash will have keys of "m" and "f". The value of $opts{m}=1, the value of $opts{f} = 'filename' and @ARGV = (1,2,3).

        You can have things like -a -f filename 1 2 3 4 or -f filename -a 1 2 3 4. Of course if somebody types in: -a -f 1 2 3 4 filename, you have to figure out that "1" isn't a filename. Anyway getopts looks for essentially space separated tokens, -3 like +3. That's the way that a C program would get the args.

        I hope this helped.

Re: Usage of flags in scripts
by MarkovChain (Sexton) on Jan 01, 2009 at 06:30 UTC