pericmd 024: Getopt::Long::Subcommand

Let’s take a look at another module in this post. If you are familiar with Getopt::Long but want to support subcommands and do not want (or have the time) to invest too much time on Perinci::CmdLine, you can try another one of my modules instead: Getopt::Long::Subcommand. That module is created precisely for the said situation.

Like Getopt::Long, it also has the GetOptions() function. But the interface is rather different, instead of an options specification hash, you supply a hash of program specification, containing keys like summary, description, and options (which is the options specification hash).

The options specification is, like in Getopt::Long, also a hash with keys like ‘foo=s’, but the value is also different. Instead of just a reference to a variable or a handler coderef, for the value you supply another hash of specification, containing keys like summary, and handler. For the handler you supply the coderef or reference to value.

The program specification can also contain the key subcommands which is where you put the subcommands. The value is a hash of subcommand names and specification. A subcommand specification is like program specification, and can also contain another key subcommands for nested subcommands.

Taken from the module’s Synopsis:

use Getopt::Long::Subcommand; # exports GetOptions

my %opts;
my $res = GetOptions(

    summary => 'Summary about your program ...',

    # common options recognized by all subcommands
    options => {
        'help|h|?' => {
            summary => 'Display help message',
            handler => sub {
                my ($cb, $val, $res) = @_;
                if ($res->{subcommand}) {
                    say "Help message for $res->{subcommand} ...";
                } else {
                    say "General help message ...";
                exit 0;
        'version|v' => {
            summary => 'Display program version',
            handler => sub {
                say "Program version $main::VERSION";
                exit 0;
        'verbose' => {
            handler => \$opts{verbose},

    # list your subcommands here
    subcommands => {
        subcmd1 => {
            summary => 'The first subcommand',
            # subcommand-specific options
            options => {
                'foo=i' => {
                    handler => \$opts{foo},
        subcmd1 => {
            summary => 'The second subcommand',
            options => {
                'bar=s' => \$opts{bar},
                'baz'   => \$opts{baz},

    # tell how to complete option value and arguments. see
    # Getopt::Long::Complete for more details, the arguments are the same
    # except there is an additional 'subcommand' that gives the subcommand
    # name.
    completion => sub {
        my %args = @_;

die "GetOptions failed!\n" unless $res->{success};
say "Running subcommand $res->{subcommand} ...";

Like in Perinci::CmdLine (and also Getopt::Long::Descriptive), you put the summary text for program, each subcommand, and each option. This allows the module to generate a nice help message for you automatically (which, unfortunately, at the time of this writing is not yet implemented).

Also like Perinci::CmdLine and Getopt::Long::Complete, there is completion support.

Unlike with Perinci::CmdLine, you write your program “conventionally”, like you would with Getopt::Long. There is no concept of Rinci metadata or Riap URL.

Also unfortunately, at the time of this writing there is no “real-world” application written using this module, because I write most of my CLI apps using Perinci::CmdLine. Aside from the example in Synopsis, there is a demo script demo-getopt-long-subcommand which shows the features as well as tab completion, but apart from that doesn’t do anything useful.


Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )


Connecting to %s