3

I am trying to setup Getopt::Long to handle the arguments from a configuration script.

Here is my starter:

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

my $config_file = '';

GetOptions (    
    'config|c=s' => \$config_file,
    'add|a' => \&add_server,
    'del|d' => \&del_server,        
);

sub add_server {    
    print "$config_file\n";    
}

sub del_server {    
    # Left blank for now.    
}

The odd thing is I am running into a problem when I run my script with something like this:

./config.pl -a -c config.xml

It does NOT print the -c option, but if I run it like this,

./config.pl -c config.xml -a

it works like it should.

I think I understand the reason why; it has to do with the order execution right?

How can I fix it? Should I use Getopt::Long in conjunction with @ARGV?

Ultimately, I am trying to make the command line args pass into the subroutine that I am calling. So if -a or --add, I want the options of -c or --config to pass into the subroutine when it is called.

Any ideas?

toolic
  • 57,801
  • 17
  • 75
  • 117
AtomicPorkchop
  • 2,625
  • 5
  • 36
  • 55

5 Answers5

4

I don't see the need to call the subroutine directly from the GetOptions call. Control the order like this:

use strict;
use warnings;
use Getopt::Long;

my %opts = (config => '');

GetOptions(\%opts, qw(
   config|c=s
   add|a
   del|d
));

add_server() if $opts{add};
del_server() if $opts{del};

sub add_server {    
    print "$opts{config}\n";
}

sub del_server {}
toolic
  • 57,801
  • 17
  • 75
  • 117
0

Boiling the example down a little bit...

use strict;
use warnings;
use Getopt::Long;

my $config_file = '';

GetOptions (

    'config|c=s' => \$config_file,
    'add|a' => sub{add_server($config_file);}
);

sub add_server
{

    my $config=shift;

    if(defined($config))
    {
        print "Got this for a config file: $config\n";
    }
    else
    {
        print "No argument supplied to add_server\n";
    }

}

... and running config.pl -c blurg -a returns the output Got this for a config file: blurg, and running config.pl -a -c blurg returns Got this for a config file:.

So, what I suspect is happening is that the options are assigned in the order given. So in the first case $config_file is assigned to the -c argument and then the add_server subroutine is called (with the correct argument), whereas in the second case, add_server is immediately fired off with no argument and then $config_file is assigned.

All this aside, I'd recommend making -a a boolean and do whatever you want to do if it's enabled (and if an argument for -c is supplied).

  • 1
    Re: "you can't associate an option directly to a code-reference to a named subroutine." Completely false. A code ref is a code ref. – ikegami Dec 13 '11 at 01:22
  • @ikegami - Upon further reading, it looks as though that's only for the exportable messages. Lemme edit. –  Dec 13 '11 at 01:53
0

The callbacks are called as the options are encountered, so add_server is being called before -c has been encountered when you do

./config.pl -a -c config.xml

Based on the latest info, you now want:

use Getopt::Long qw( GetOptions );

GetOptions(
   'a=s' => \my $opt_a,
   'd=s' => \my $opt_d,
   'h=s' => \my $opt_h,
   'p=s' => \my $opt_p,
) or usage();
ikegami
  • 367,544
  • 15
  • 269
  • 518
  • I only need to specify a single config file. – AtomicPorkchop Dec 13 '11 at 03:19
  • 1
    @Solignis, Why not just do `-a config.xml`, then? – ikegami Dec 13 '11 at 03:32
  • 1
    @Solignis, Why don't you specify what interface you do want before this becomes a game of 20 questions. – ikegami Dec 13 '11 at 03:33
  • The original idea was to have `-a` and `-d` control the specific section of the config you wish to add or delete. For example `-a server01` would call the `add_server` subroutine with the option `server01` But I could not figure out how to get one option to do two things without getting messy. – AtomicPorkchop Dec 13 '11 at 03:37
  • 1
    @Solignis, Q2) Which option should do two things? Q3) What two things should it do? – ikegami Dec 13 '11 at 05:07
  • @Solignis, I forgot to mention that I updated based on your last message. Still had to make many guesses due to the lack of spec. – ikegami Dec 13 '11 at 18:57
  • When you mean lack of spec what do you need to know. I am sorta of creating this "on the fly" and just trying to shape out something. The basic idea is I am trying to make a small script that creates a config file for another program. I want the script to take inputs for the mode `-a, -d` (for now) and inputs for the options like `-h for host` `-p for port` etc.. The biggest thing I am trying to accompish is something that has lots of "safety" so when it encounters and invalid option it stops instead of moving on which is what does with everything I tried. Follow me? – AtomicPorkchop Dec 14 '11 at 05:12
  • @Solignis, Wow, you didn't say any of this before!!! Post updated for lastest spec. Except for the moving on part. Using GetOptions to get behaviour other than GetOptions is not gonna work. – ikegami Dec 14 '11 at 07:30
  • So if I trying to use GetOptions in the wrong way then what would be a better method? Use @ARGV to capture the primary mode I wish to run then use GetOptions to capture the options like $config_file? – AtomicPorkchop Dec 14 '11 at 08:22
  • 1
    @Solignis, I would recommend removing the requirement that some errors should be kept hidden. – ikegami Dec 14 '11 at 08:24
-1

Enable the pass_through option on Getopt::Long so that it will ignore unknown options, then call GetOptions once for your options, disable it again, and then use GetOptions again for your command.

Christopher Neylan
  • 8,018
  • 3
  • 38
  • 51
-2
GetOptions(
        'arg=s' => sub { print "$_[1]\n"; },
);
hugg
  • 1
  • 1
    Sorry, I thought it would be self explaning. The `GetOptions()` function passes the parameters array `@_` to the whatever_you_like function that is referenced as argument action. The array contains the full name of the argument (`arg`) in $_[0] and it's value in $_[1]. – hugg Jul 03 '14 at 06:05