In Perl 5, I can use Getopt::Long
to parse commandline arguments with some validation (see below from http://perldoc.perl.org/Getopt/Long.html).
use Getopt::Long;
my $data = "file.dat";
my $length = 24;
my $verbose;
GetOptions ("length=i" => \$length, # numeric
"file=s" => \$data, # string
"verbose" => \$verbose) # flag
or die("Error in command line arguments\n");
say $length;
say $data;
say $verbose;
Here =i
in "length=i"
creates a numeric type constraint on the value associated with --length
and =s
in "file=s"
creates a similar string type constraint.
How do I do something similar in Raku (née Perl 6)?
The @ARGV array holds the command line argument. There is no need to use variables even if you use "use strict". By default, this variable always exists and values from the command line are automatically placed inside this variable. To access your script's command-line arguments, you just need to read from @ARGV array.
That feature is built into Raku (formerly known as Perl 6). Here is the equivalent of your Getopt::Long
code in Raku:
sub MAIN ( Str :$file = "file.dat"
, Num :$length = Num(24)
, Bool :$verbose = False
)
{
$file.say;
$length.say;
$verbose.say;
}
MAIN
is a special subroutine that automatically parses command line arguments based on its signature.
Str
and Num
provide string and numeric type constraints.
Bool
makes $verbose
a binary flag which is False
if absent or if called as --/verbose
. (The /
in --/foo
is a common Unix command line syntax for setting an argument to False
).
:
prepended to the variables in the subroutine signature makes them named (instead of positional) parameters.
Defaults are provided using $variable =
followed by the default value.
If you want single character or other aliases, you can use the :f(:$foo)
syntax.
sub MAIN ( Str :f(:$file) = "file.dat"
, Num :l(:$length) = Num(24)
, Bool :v(:$verbose) = False
)
{
$file.say;
$length.say;
$verbose.say;
}
:x(:$smth)
makes additional alias for --smth
such as short alias -x
in this example. Multiple aliases and fully-named is available too, here is an example: :foo(:x(:bar(:y(:$baz))))
will get you --foo
, -x
, --bar
, -y
and --baz
and if any of them will pass to $baz
.
MAIN
can also be used with positional arguments. For example, here is Guess the number (from Rosetta Code). It defaults to a min of 0 and max of 100, but any min and max number could be entered. Using is copy
allows the parameter to be changed within the subroutine:
#!/bin/env perl6
multi MAIN
#= Guessing game (defaults: min=0 and max=100)
{
MAIN(0, 100)
}
multi MAIN ( $max )
#= Guessing game (min defaults to 0)
{
MAIN(0, $max)
}
multi MAIN
#= Guessing game
( $min is copy #= minimum of range of numbers to guess
, $max is copy #= maximum of range of numbers to guess
)
{
#swap min and max if min is lower
if $min > $max { ($min, $max) = ($max, $min) }
say "Think of a number between $min and $max and I'll guess it!";
while $min <= $max {
my $guess = (($max + $min)/2).floor;
given lc prompt "My guess is $guess. Is your number higher, lower or equal (or quit)? (h/l/e/q)" {
when /^e/ { say "I knew it!"; exit }
when /^h/ { $min = $guess + 1 }
when /^l/ { $max = $guess }
when /^q/ { say "quiting"; exit }
default { say "WHAT!?!?!" }
}
}
say "How can your number be both higher and lower than $max?!?!?";
}
Also, if your command line arguments don't match a MAIN
signature, you get a useful usage message, by default. Notice how subroutine and parameter comments starting with #=
are smartly incorporated into this usage message:
./guess --help
Usage:
./guess -- Guessing game (defaults: min=0 and max=100)
./guess <max> -- Guessing game (min defaults to 0)
./guess <min> <max> -- Guessing game
<min> minimum of range of numbers to guess
<max> maximum of range of numbers to guess
Here --help
isn't a defined command line parameter, thus triggering this usage message.
See also the 2010, 2014, and 2018 Perl 6 advent calendar posts on MAIN
, the post Parsing command line arguments in Perl 6, and the section of Synopsis 6 about MAIN.
Alternatively, there is a Getopt::Long for perl6 too. Your program works in it with almost no modifications:
use Getopt::Long;
my $data = "file.dat";
my $length = 24;
my $verbose;
get-options("length=i" => $length, # numeric
"file=s" => $data, # string
"verbose" => $verbose); # flag
say $length;
say $data;
say $verbose;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With