Perl Getopt::Long question - stopping multiple args

Hi there, I have an example basic script (below) and ive been trying to figure out how to stop multiple arguments to my options occuring. for example using the example script below I can issue two arguments for, say the --surname option and it will not barf at me (although thats what i want it to do). It just ignores the second argument to the --surname option completely and happily continues.

#./name.pl --firstname John --surname Smith Jones
firstname is set to  - John
surname is set to  - Smith

How would i get it to barf at me for providing too many options ?

Any help would be great

The Script

#!/bin/perl

use strict;
use Getopt::Long;

my $firstname = "";
my $surname = "";
my $help = "";

GetOptions (
                "firstname=s"           => \$firstname,
                "surname=s"             => \$surname,
                "help!"                 => \$help,

                ) or die "Incorrect usage.\n";


if( $help )
{
        print "Common on, it's really not that hard.\n";
} else {



        if (!$firstname) { print "You have failed to enter a --firstname value\n"; exit 11 }
        if (!$surname) { print "You have failed to enter a --surname value\n"; exit 12 }


        print "firstname is set to  - $firstname\n";
        print "surname is set to  - $surname\n";

}

Getopt::Long won't stop on any usage that isn't explicitly forbidden by it's internals. One way would be to allow multiple values for Getopt::Long, and throw an error yourself if the resulting array contains more than 1 value.

---------- Post updated at 14:55 ---------- Previous update was at 14:53 ----------

Or define your own subroutine handler for that option.

Thanks Pludi, Ive been playing around and i wonder if you could help me clarify something. I changed the relevant lines (bolded in red below) to make surname an array (which looks like it creates a reference to the array). but it still seems to print only the one argument ?

Am i missing something here? Will a scalar reference to an array always only return the first object in an array ? apologies if ive done something dumb here

#!/bin/perl
use strict;
use Getopt::Long;

my $firstname = "";
my $surname = "";
my $help = "";

GetOptions (
                "firstname=s"           => \$firstname,
                "surname=s@"             => \$surname,
                "help!"                 => \$help,

                ) or die "Incorrect usage.\n";

if( $help )
{
        print "Common on, it's really not that hard.\n";
} else {

        print "firstname is set to  - @$firstname\n";
        print "surname is set to  - $surname\n";

}

As you can see its still the same

# ./name.pl --firstname John --surname smith jones    
firstname is set to  - John
surname is set to  - smith

I tried it using this as well

"surname=s"             => \@surname

...
...

print "surname is set to  - @surname\n";

with the same output, so maybe its not just an issue with references

Good thing they provide an example with the documentation.

#!/bin/perl
use strict;
use Getopt::Long;

my $firstname = "";
my @surname   = ();
my $help      = "";

GetOptions(
    "firstname=s" => \$firstname,
    "surname=s@"  => \@surname,
    "help!"       => \$help,

) or die "Incorrect usage.\n";

if ($help) {
    print "Common on, it's really not that hard.\n";
}
else {

    print "firstname is set to  - $firstname\n";
    print "surname is set to  - @surname\n";

}
$ perl getopt.pl --firstname John --surname Smith --surname Jones
firstname is set to  - John
surname is set to  - Smith Jones

Sorry Pludi, i think you may have misunderstood my problem, issuing multiple --surnames is not really the problem, its when they issue multiple arguments to the same --surname option

using the exact script you posted above, i issued

 # ./name.pl --firstname john --surname smith jones
firstname is set to  - john
surname is set to  - smith 

wjen we print the array at the bottom of the script, the second argument is not printed

Ah, you mean like the example a few paragraphs down in the documentation?

#!/bin/perl
use strict;
use Getopt::Long;

my $firstname = "";
my @surname   = ();
my $help      = "";

GetOptions(
    "firstname=s"   => \$firstname,
    "surname=s{1,}" => \@surname,
    "help!"         => \$help,

) or die "Incorrect usage.\n";

if ($help) {
    print "Common on, it's really not that hard.\n";
}
else {

    print "firstname is set to  - $firstname\n";
    print "surname is set to  - @surname\n";

}
$ perl getopt.pl --firstname John --surname Smith Jones
firstname is set to  - John
surname is set to  - Smith Jones

Pludi, I apologise. I must have read through that documentaion 3 times but seem to have been overwhelmed by the information and missed the paragraph that i needed... Thank you for your help

---------- Post updated at 11:12 AM ---------- Previous update was at 06:14 AM ----------

Bah, would you believe it the "option=s{'1,}" functionality is only available in 5.10 by the looks of it, all my systems are perl 5.8 or less .

I get this error when running the script on 5.8 or below

# ./name.pl  
Error in option spec: "surname=s{1,}"

:frowning: oh well

I don't think so:

$ perl --version

This is perl, v5.8.8 built for i486-linux-gnu-thread-multi

Copyright 1987-2006, Larry Wall

Perl may be copied only under the terms of either the Artistic License or the
GNU General Public License, which may be found in the Perl 5 source kit.

Complete documentation for Perl, including FAQ lists, should be found on
this system using "man perl" or "perldoc perl".  If you have access to the
Internet, point your browser at http://www.perl.org/, the Perl Home Page.

$ perl test.pl --firstname John --surname Woo Wayne
firstname is set to  - John
surname is set to  - Woo Wayne

Getopt::Long is 2.35, you can check this in the headers of (probably) /usr/share/perl/5.8/Getopt/Long.pm

I have a mixture of solaris 8 and 10. this is the module information of one of my more recent boxes

# cat /usr/perl5/5.8.4/lib/Getopt/Long.pm | more
# Getopt::Long.pm -- Universal options parsing

package Getopt::Long;

# RCS Status      : $Id: GetoptLong.pm,v 2.68 2003-09-23 15:24:53+02 jv Exp $
# Author          : Johan Vromans
# Created On      : Tue Sep 11 15:00:12 1990
# Last Modified By: Johan Vromans
# Last Modified On: Tue Sep 23 15:21:23 2003
# Update Count    : 1364
# Status          : Released

################ Copyright ################

# This program is Copyright 1990,2002 by Johan Vromans.
# This program is free software; you can redistribute it and/or
# modify it under the terms of the Perl Artistic License or the
# GNU General Public License as published by the Free Software
# Foundation; either version 2 of the License, or (at your option) any
# later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# If you do not have a copy of the GNU General Public License write to
# the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
# MA 02139, USA.

################ Module Preamble ################

use 5.004;

use strict;

use vars qw($VERSION);
$VERSION        =  2.34;

maybe they added this code in 2.35 ?

Could be. Try fetching the current version from CPAN, and install it non-globally first. If everything works out, install it for the whole machine/all machines.

in my environment I would have more chance of squeezing blood from a stone than getting the required signoff to update perl on all my systems :frowning:

I may use the bash getopts_long by Stephane Chazelas as ive been working with this one for ages and i know how to get around the problem

thankyou for your help though Pludi (as always)

Well, if all else fails, ship the module as part of your script. Either in a file of its own, with a

use lib '.'; # Include current directory

or by simply appending it to the bottom of your script. Simple example:

#!/usr/bin/perl

use strict;
use warnings;

print "I'm the main script\n";
Foo::Bar();
Foo->new()->Bar();
print "I'm the main script again\n";

package Foo;

sub Bar {
    my ($self) = @_;
    if ( ref $self eq "Foo" ) {
        print "I'm Foo->Bar()\n";
    }
    else {
        print "I'm Foo::Bar()\n";
    }
}

sub new {
    my ($class) = @_;
    my $self = {};
    bless( $self, $class );
    return $self;
}
1;
$ perl pkg.pl
I'm the main script
I'm Foo::Bar()
I'm Foo->Bar()
I'm the main script again