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

Well, lately I have had the pleasure of working on commandline scripts instead of the usual CGIs. For the first time, I have delved into Getopts::Long which is cool and all, but it has the annoying behavior that allows a switch that takes a string to have that string start with a "-".

How do I change this behavior? Right now, if I do this:

myscript.pl -file -name

file will be set to "-name" which is undesirable because I have name set to be an option as well. I have written a solution but was hoping someone might now of a configuration option that would allow me to avoid the workaround.


I admit it, I am Paco.

Replies are listed 'Best First'.
Re: Getopts::Long -- changing its behavior
by djantzen (Priest) on Feb 06, 2002 at 03:33 UTC

    Getopt::Long in this case is just letting you be flexible -- the '-' is a valid character in a string, so it lets you put it in there. What I've done in the past is set up a collection of regular expressions to validate the strings passed in. You can do this after argument processing, or during using anonymous subs.

    This ain't pretty, but it'll work.

    my %script_opts = (); GetOptions("foo=s" => sub { if ($_[1] =~ /^([^-]).*$/) { $script_opts{$_[0]} = $_[1];} } );

    Documentation for the module is here.

Re: Getopts::Long -- changing its behavior
by lachoy (Parson) on Feb 06, 2002 at 04:02 UTC

    You don't mention how you initialize Getopt::Long, but you should be able to define 'file' as a boolean switch rather than a value field. Running the following:

    #!/usr/bin/perl use strict; use Getopt::Long; my ( $file, $name ); GetOptions( file => \$file, name => \$name ); print "File: $file\nName: $name\n";

    with:

    perl test_getopt.pl -file -name

    produces:

    File: 1 Name: 1

    which sounds like what you want.

    Chris
    M-x auto-bs-mode

      Nope. What I want is to be able to do:

      myscript.pl -file -name

      And get the error that -file requires a string. In the case here, I don't get the error. I get file set to "-name". In other words, I want getopts to recognize that a switch has followed the one I wanted to take a string instead of a string as a required, so the user does not need to worry about what order s/he puts the switch in.


      I admit it, I am Paco.
        Something like this might do what you need:
        GetOptions(\%param, 'file:s', 'name:s', 'any:s', 'other:s', 'params:s' +); foreach (qw(file name any other params)) { die "Option $_ requires an argument\n" if defined($param{$_}) && $pa +ram{$_} eq ''; }

        Using the colon (e.g. 'file:s') in the GetOptions call instead of an equals sign makes a string parameter on the switch optional rather than required. As a result, when GetOptions sees '-file -name', it interprets this as 'switch -file with no optional string param, followed by switch -name with no optional string param', rather than as 'switch -file with string param -name'. Then the subsequent loop goes through and complains if one of those "optional" parameters in fact has an empty value.

        Also, if you check the perldoc for Getopt::Long you'll find that you can define handler subroutines to be called when an individual switch is encountered, which would probably also let you trap the case that's bothering you. I haven't used that capability in a while and it seems like it would be more work, but perhaps I haven't addressed all the angles of your question.

        Good luck!