I am trying to use the GetOptions
function from GetOpt::Long
to call a subroutine that accepts an argument. However, the subroutine gets called regardless of whether the option is specified on the command line. This unexpected behavior does not occur if an argument is not passed to the subroutine in the GetOptions
line.
What follows is a minimal demonstration of the problem:
If an argument is provided to the subroutine in the GetOptions
line, the subroutine ends up being called regardless of whether its controlling option is supplied on the command line:
$ cat a1.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
my $var="entered";
GetOptions ( "opt" => \&sub1($var) );
sub sub1 { print "sub1 $_[0]\n"; }
$ perl a1.pl --opt
sub1 entered
$ perl a1.pl
sub1 entered
In contrast, if the subroutine is called in GetOptions
without an argument, it behaves appropriately:
$ cat a2.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
GetOptions ( "opt" => \&sub2 );
sub sub2 { print "sub2 entered\n"; }
$ perl a2.pl --opt
sub2 entered
$ perl a2.pl
What am I doing wrong?
PS: I know that I can simply set a variable that controls whether the subroutine is called after the GetOptions
block, but I would like to determine the correct syntax for calling the subroutine within the GetOptions
line, as well as understand why the observed behavior is happening.
The module expects a code reference, and that is taken with the sub name alone (\&name
) or as an anonymous sub; there is no notion of "arguments" as you are not making a function call but rather obtaining a reference (to code). Then call you sub in that code. Details follow.
Associate the option with an anonymous subroutine, inside of which you can call your sub
use warnings;
use strict;
use feature 'say';
use Getopt::Long;
my $opt;
my $var = 'entered';
GetOptions ( 'opt' => sub { $opt = 1; sub1($var) } );
sub sub1 { say "sub1 $_[0]"; }
Or use 'opt' => \&cb
and in the sub cb()
call sub1(...)
. This callback is passed the option name and value (or name, key, and value in case of a hash), and doesn't take other arguments. So you cannot in any way dynamically resolve what arguments to pass to sub1()
.
The invocation in the question is not how a subroutine reference is obtained; you must only use the subroutine name, \&name
. This is not about Getopt
, which just wants a code reference.
When you attempt to "pass arguments" that isn't a coderef anymore but the sub is executed and then the reference taken of its return; same as \sub()
or \( sub() )
. This can be seen by
perl -wE'sub tt { say "@_"; return "ret" }; $r = \&tt("hi"); say $$r'
what prints
hi ret
While this just isn't a way to take a reference let me still warn of possible surprises (if one ends up trying to take a "reference to a list")