Reputation: 62224
I'm looking for an easy way to check for a correct number of command line parameters, displaying a usage message if an error occurs and then immediately exit.
I thought of something like
if (@ARGV < 3) {
print STDERR "Usage: $0 PATTERN [FILE...]\n";
exit 1;
}
Is this a valid pattern?
Upvotes: 15
Views: 41871
Reputation: 4391
Actually it depends on your level of distrust (you did not specify what parameters are actually expected):
@ARGV < 3
just checks whether there are less than three parametersAs suggested in https://stackoverflow.com/a/5022789/6607497 using Getopt::Long
is a first step, but even arg1=s
will allow the string to be anything, even empty.
As said above, you can extend Getopt::Long
with your own checking functions (that would exceed the typical size of an answer, specifically when considering the very short (and little detailed) question), but a pattern could look like this:
# parse options
sub get_options()
{
my $result = 1;
my %options = ('angular-offset=f' => \$angular_offset,
'destination-point=s' => check_pair_param(\@p_dest),
'iteration-count=i' => check_positive_param(\$count),
'speed=f' => check_speed_param(\$speed),
'starting-point=s' => check_pair_param(\@p_start),
'translation-vector=s' => check_pair_param(\@v_transl),
'verbosity=i' => \$verbosity);
use Getopt::Long;
if (!GetOptions(%options))
{
print STDERR "valid options for $0 are:\n";
foreach my $opt (sort(keys %options)) {
#...
}
print STDERR "\n";
undef $result;
}
return $result;
}
In the example check_positive_param
will check whether the parameter is a positive number (GetOptions
and =i
ensures that it's an integer already), maybe like this (warning: closures ahead):
# check for positive number
sub check_positive_param($)
{
my $tgt_ref = shift;
sub (;$$) {
my ($name, $value) = @_;
unless (defined($value)) { # printable representation
return $tgt_ref;
} elsif ($value && $value > 0) {
$$tgt_ref = $value;
} else {
$name = '--' . $name;
die "$value: not a positive value for $name!\n";
}
}
}
The closure also allows to print the value of the associated option variable, and the reason for using a closure is that you can check different option values that all need to be positive.
For example specifying --it=-4
would result in an error message like this:
-4: not a positive value for --iteration-count!
valid options for ../homing.pl are:
...
Similar checks could be written to check for existing files, readable files, valid host names, etc.
For repeating options where values are collected in arrays, it's a bit more tricky, but it works as well.
I'm not saying it's the most elegant way to do it, but it works rather well (also showing the list of valid options and their default value (in the part that is omitted), but that also wasn't part of the question).
Upvotes: 0
Reputation: 5114
Use $#ARGV to get total number of passed argument to a perl script like so:
if (@#ARGV < 4)
I've used before and worked as shown in http://www.cyberciti.biz/faq/howto-pass-perl-command-line-arguments/.
See the original documentation at http://perldoc.perl.org/perlvar.html, it states that:
@ARGV
The array @ARGV contains the command-line arguments intended for the script. $#ARGV is generally the number of arguments minus one, because $ARGV[0] is the first argument, not the program's command name itself. See $0 for the command name.
Upvotes: 1
Reputation: 129489
Also, I would STRONGLY suggest using the idiomatic way of processing command line arguments in Perl, Getopt::Long
module (and start using named parameters and not position-based ones).
You don't really CARE if you have <3 parameters. You usually care if you have parameters a, b and C present.
As far as command line interface design, 3 parameters is about where the cut-off is between positional parameters (cmd <arg1> <arg2>
) vs. named parameters in any order (cmd -arg1 <arg1> -arg2 <arg2>
).
So you are better off doing:
use Getopt::Long;
my %args;
GetOptions(\%args,
"arg1=s",
"arg2=s",
"arg3=s",
) or die "Invalid arguments!";
die "Missing -arg1!" unless $args{arg1};
die "Missing -arg2!" unless $args{arg2};
die "Missing -arg3!" unless $args{arg3};
Upvotes: 33
Reputation: 1540
You can compare with $#ARGV instead the array @ARGV
if ($#ARGV < 3) { ...
Upvotes: -3
Reputation: 62227
Another common way to do that is to use die
die "Usage: $0 PATTERN [FILE...]\n" if @ARGV < 3;
You can get more help on the @ARGV
special variable at your command line:
perldoc -v @ARGV
Upvotes: 15
Reputation: 14164
Yes, it is fine. @ARGV
contains the command-line arguments and evaluates in scalar context to their number.
(Though it looks like you meant @ARGV < 2
or < 1
from your error message.)
Upvotes: 6