Getopt::Long's argument callback feature ("<>") may help here. The idea is to call GetOptions twice: first time with the global options, and to stop on the first unrecognized non-option. This one may be an invalid global option, or a subcmd, either valid or invalid. After this, call GetOptions again with the remaining arguments which would all be subcmd options.
#!/usr/bin/perl
use strict;
use Getopt::Long;
my $subcmd;
my $global_option;
my $subcmd_option;
GetOptions("global" => \$global_option,
"<>" => sub {
my($arg) = @_;
if ($arg =~ m{^-}) {
die "usage error: unhandled option $arg detected in
+ global option section";
} elsif ($arg !~ m{^(subcmd1|subcmd2)$}) {
die "usage error: invalid subcommand $arg";
} else {
$subcmd = $arg;
die "!FINISH";
}
})
or die "usage error (in global option section)";
GetOptions("subcmd" => \$subcmd_option)
or die "usage error (in subcmd option section)";
print <<EOF;
global_option: $global_option
subcmd: $subcmd
subcmd_option: $subcmd_option
leftover: @ARGV
EOF
__END__