Command Line Subcommands in Perl
Here’s the translation of the Go code example to Perl, formatted in Markdown suitable for Hugo:
Our first program demonstrates how to create command-line subcommands with their own set of flags. This is similar to how tools like git
have subcommands like git commit
and git push
, each with their own options.
#!/usr/bin/env perl
use strict;
use warnings;
use Getopt::Long qw(GetOptionsFromArray);
use Pod::Usage;
sub main {
# We declare subcommands and their specific options
my %commands = (
'foo' => \&cmd_foo,
'bar' => \&cmd_bar,
);
# The subcommand is expected as the first argument to the program
if (@ARGV < 1) {
print "expected 'foo' or 'bar' subcommands\n";
exit 1;
}
my $command = shift @ARGV;
# Check which subcommand is invoked
if (exists $commands{$command}) {
$commands{$command}->();
} else {
print "expected 'foo' or 'bar' subcommands\n";
exit 1;
}
}
# For every subcommand, we parse its own flags and
# have access to trailing positional arguments
sub cmd_foo {
my $enable = 0;
my $name = '';
GetOptionsFromArray(
\@ARGV,
"enable" => \$enable,
"name=s" => \$name,
) or pod2usage(2);
print "subcommand 'foo'\n";
print " enable: ", $enable ? "true" : "false", "\n";
print " name: $name\n";
print " tail: [", join(", ", @ARGV), "]\n";
}
sub cmd_bar {
my $level = 0;
GetOptionsFromArray(
\@ARGV,
"level=i" => \$level,
) or pod2usage(2);
print "subcommand 'bar'\n";
print " level: $level\n";
print " tail: [", join(", ", @ARGV), "]\n";
}
main();
__END__
=head1 NAME
subcommands - Example of command-line subcommands
=head1 SYNOPSIS
subcommands foo [options] [args]
subcommands bar [options] [args]
Options for foo:
--enable Enable flag
--name=STRING Name option
Options for bar:
--level=INT Level option
=cut
To run the program, save it as subcommands.pl
and make it executable:
$ chmod +x subcommands.pl
First, invoke the foo subcommand:
$ ./subcommands.pl foo --enable --name=joe a1 a2
subcommand 'foo'
enable: true
name: joe
tail: [a1, a2]
Now try bar:
$ ./subcommands.pl bar --level 8 a1
subcommand 'bar'
level: 8
tail: [a1]
But bar won’t accept foo’s flags:
$ ./subcommands.pl bar --enable a1
Unknown option: enable
Usage:
subcommands bar [options] [args]
Options for bar:
--level=INT Level option
This Perl script demonstrates how to create a program with subcommands, each having its own set of options. It uses the Getopt::Long
module to parse command-line options and Pod::Usage
for generating usage information.
The structure is similar to the original example, with separate functions for each subcommand (cmd_foo
and cmd_bar
). The main function checks the first argument to determine which subcommand to run, then delegates to the appropriate function.
Each subcommand function uses GetOptionsFromArray
to parse its specific options, allowing for different sets of flags for each subcommand. Any remaining arguments are treated as positional arguments.
This approach allows for creating complex command-line tools with multiple subcommands, each with its own set of options and behaviors.