http://www.perlmonks.org?node_id=1045727

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

hi,

i'm trying to invoke a subroutine on the occurrence of certain option, say something like this

GetOptions( 'test=s{3}' => \&sub1 ); sub sub1 { print @_ }

running the script with

prog --test a b c

would yield a result like this

test a

test b

test c

as if the sub was called 3 times, each with 1 of the 3 values passed in, how do i make it so that all 3 values of the option are passed to @_ once with one invocation of the subroutine?

Replies are listed 'Best First'.
Re: Getopt::Long subroutine question
by Loops (Curate) on Jul 22, 2013 at 21:27 UTC

    You can't use a sub reference like that if your desire is for it to receive all the parameters at once. Here is an alternative:

    use strict; use warnings; use Getopt::Long; my @test; GetOptions( 'test=s{3}' => \@test ); sub sub1 { print "@_" }; sub1 @test if @test;
Re: Getopt::Long subroutine question
by 2teez (Vicar) on Jul 23, 2013 at 03:48 UTC

    hi brassbin,
    *as if the sub was called 3 times, how do i make it so that all 3 values of the option are passed to @_ once with one invocation of the subroutine?

    Checking the User-defined subroutines to handle options in Getopt::Long documentation, it says

    Ultimate control over what should be done when (actually: each time) an option is encountered on the command line can be achieved by designating a reference to a subroutine (or an anonymous subroutine) as the option destination. When GetOptions() encounters the option, it will call the subroutine with two or three arguments. The first argument is the name of the option. (Actually, it is an object that stringifies to the name of the option.) For a scalar or array destination, the second argument is the value to be stored...

    And if I get that right something like this:
    use warnings; use strict; use Getopt::Long; GetOptions('test=s{3}'=>\&sub1); sub sub1{ print $_[1]; }
    NOTE: If the is less than what is specified, you get a message of Insufficient arguments for option ....

    UPDATE: * Re^3: Getopt::Long subroutine question

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me
      Hi 2teez,

      From my reading of that documentation the my original answer still is correct. Your code calls sub1 3 times (once for each parameter passed on the command line). Yet the OP asked how to have the sub called just once with all parameters in tow.

        Yes, you are right, however, what I intend to answer, is the OP words ..as if the sub was called 3 times..
        That was why I quoted the documentation, that though the sub is called each time an option is encountered, however it could be shown as though those options were gotten once!! Accessing only the the value to be stored, in this case a,b and c NOT like the OP has it test a, test b and test c.

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me
Re: Getopt::Long subroutine question
by kcott (Archbishop) on Jul 23, 2013 at 13:38 UTC

    G'day brassbin,

    If we knew what problem you were attempting to solve with this requirement, you'd probably get better answers.

    If you moved the checking of 3 values (i.e. s{3}) from GetOptions() to sub1() and passed --test a string containing the values, you could do something like this:

    $ perl -Mstrict -Mwarnings -le ' use Getopt::Long; sub sub1 { my ($name, $value) = @_; my $want = 3; my @got = split /\s+/ => $value; die "--$name requires $want values. Got: @got\n" unless @got = += $want; print "$name $_" for @got; } GetOptions( "test=s" => \&sub1 ); ' -- --test 'a b c' test a test b test c

    And with the wrong number of values:

    $ perl -Mstrict -Mwarnings -le ' ... ' -- --test 'a b' --test requires 3 values. Got: a b
    $ perl -Mstrict -Mwarnings -le ' ... ' -- --test 'a b c d' --test requires 3 values. Got: a b c d

    Additional Information Update: You wrote "as if the sub was called 3 times". It's not "as if", that's exactly what's happening. This shows each separate call with the individual arguments highlighted:

    $ perl -Mstrict -Mwarnings -E ' use Getopt::Long; sub sub1 { state $i = 0; ++$i; say "$i: >>>$_<<<" for @_ } GetOptions( "test=s{3}" => \&sub1 ); ' -- --test a b c 1: >>>test<<< 1: >>>a<<< 2: >>>test<<< 2: >>>b<<< 3: >>>test<<< 3: >>>c<<<

    -- Ken

      Thank you all for your help! now i read the documentation again, it does seem to imply that, wish it could be a bit more less stingy in terms of elaborating on parameter-passing to subroutines :-)