Basics

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.

Aliases

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.

Positional arguments (and example)

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?!?!?";
}

Usage message

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

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.

Answer from Christopher Bottoms on Stack Overflow
🌐
Raku Documentation
docs.raku.org › type › Proc › Async
class Proc::Async | Raku Documentation
The :started attribute is set by ... just need to start an external program immediately. On Windows the flag $win-verbatim-args disables all automatic quoting of process arguments....
🌐
Raku Documentation
docs.raku.org › routine › run
run | Raku Documentation
It is an error to run a thread that has already been started. See primary documentation in context for sub run. ... sub run( *@args ($, *@), :$in = '-', :$out = '-', :$err = '-', Bool :$bin = False, Bool :$chomp = True, Bool :$merge = False, Str:D :$enc = 'UTF-8', Str:D :$nl = "\n", :$cwd = ...
🌐
Raku
raku.github.io › Documentable › integration-test › routine › spawn
method spawn
On Windows the flag $win-verbatim-args disables all automatic quoting of process arguments. See this blog for more information on windows command quoting. The flag is ignored on all other platforms. The flag was introduced in Rakudo version 2020.06 and is not present in older releases.
🌐
Raku Documentation
docs.raku.org › type › Proc
class Proc | Raku Documentation
On Windows the flag $win-verbatim-args disables all automatic quoting of process arguments. See this blog for more information on windows command quoting. The flag is ignored on all other platforms.
🌐
GitHub
github.com › Raku › doc › issues › 3495
Checklist for 2020.06 · Issue #3495 · Raku/doc
March 28, 2020 - If STDIN is not connected to a terminal, then Raku will read from STDIN and process that as the source of a program. The run routine, Proc.spawn and Proc::Async.new are extended with a new argument :$win-verbatim-args defaulting to False.
Published   Jun 21, 2020
Top answer
1 of 2
20

Basics

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.

Aliases

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.

Positional arguments (and example)

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?!?!?";
}

Usage message

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

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.

2 of 2
5

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;
🌐
Perl6
docs.perl6.org › routine › run
run | Raku Documentation
Raku highlighting · sub run( *@args ($, *@), :$in = '-', :$out = '-', :$err = '-', Bool :$bin = False, Bool :$chomp = True, Bool :$merge = False, Str:D :$enc = 'UTF-8', Str:D :$nl = "\n", :$cwd = $*CWD, Hash() :$env = %*ENV, :$arg0, :$win-verbatim-args = False ·
🌐
Raku Documentation
docs.raku.org › language › create-cli
Command line interface | Raku Documentation
Whether you should use either method to achieve the desired goal is entirely up to you. If you want to pass an indeterminate number of parameters to be dealt with in sub MAIN, you can use slurpy parameters: ... A more complicated example using a single positional and multiple named parameters, and also showing that where clauses can also be applied to MAIN arguments:
🌐
JJA
pinguinorodriguez.cl › blog › raku-argument-parsing
Sharing command line parameters in Raku | JJA
November 11, 2020 - Raku has built-in support for writing command line interfaces. If a file has a MAIN subroutine, it will called automatically when the file is directly executed. And more interestingly will use that subroutine’s signature to automatically parse the command line arguments.
Find elsewhere
🌐
Raku Guide
raku.guide
Raku Guide
If a function is allowed to run through it’s block to the end, the last statement or expression will determine the return value. ... For the sake of clarity, it might be a good idea to explicitly specify what we want returned. This can be done using the return keyword. ... In one of the previous examples, we saw how we can restrict the accepted argument to be of a certain type.
🌐
Rosetta Code
rosettacode.org › wiki › Command-line_arguments
Command-line arguments - Rosetta Code
3 weeks ago - For this example we make a script, save to temporary directory, and call it passing arguments. We can use Win as shell substitute in M2000 environment, or the Use statement. Reading the shell statement Win we can see how the command line composed. We call the m2000.exe in the appdir$ (application directory, is the path to M2000.exe), and pass a string as a file with a path.
🌐
Andrewshitov
andrewshitov.com › 2018 › 12 › 20 › using-command-line-options-in-perl-6-one-liners
🎄 20/25. Using command-line options in Raku one-liners – Andrew Shitov
Welcome to Day 20 of the Perl 6 One-Liner Advent Calendar! So far, we created about 25 different one-liners, but never talked about the command-line options that the Rakudo Perl 6 compiler offers to us.
🌐
Raku
raku.org
Raku Programming Language
Linux, macOS, Windows, Docker · Smoothly combine coding styles:
🌐
Andrewshitov
andrewshitov.com › 2018 › 10 › 31 › working-with-files-and-directories-in-perl-6
📘 Working with files and directories in Raku – Andrew Shitov
By default, either a new destination file will be created or rewritten if it already exists. You can open the file in the append mode by adding the :append value in the third argument:
🌐
Buttondown
buttondown.com › hillelwayne › archive › raku-is-surprisingly-good-for-clis
Raku is surprisingly good for CLIs • Buttondown
October 26, 2023 - You can define the special hash %*SUB-MAIN-OPTS to configure how the arguments are parsed. F.ex if you add the :bundling key, then it will accept -abc in addition to -a -b -c. Raku provides some hooks to override CLI behavior, like if you define the ARGS-TO-CAPTURE function you can preprocess arguments before dispatching to MAIN.
🌐
Andrewshitov
andrewshitov.com › 2018 › 10 › 31 › slurpy-parameters-and-flattening-in-perl-6
📘 Slurpy parameters and flattening in Raku – Andrew Shitov
Its grammar, syntax, sigils, and ... 6 as Raku. You are reading the article written before the rename. What is said here, most likely still works, but you may want considering to review the differences after the rename. The texts published on this site prior to the rename will stay unchanged for reflecting the historical truth. Perl 6 allows passing scalars, arrays, hashes, or objects of any other type as the arguments to a ...
🌐
Raku Documentation
docs.raku.org › routine › MAIN
MAIN | Raku Documentation
The sub with the special name MAIN will be executed after all relevant entry phasers (BEGIN, CHECK, INIT, PRE, ENTER) have been run and the mainline of the script has been executed. No error will occur if there is no MAIN sub: your script will then just have to do the work, such as argument ...
🌐
Raku
course.raku.org › essentials › the-main-function › reading-command-line-arguments
Reading command line arguments
There are two ways of reading command-line arguments. One of them is via the @*ARGS array, which we already used.
🌐
Andrewshitov
andrewshitov.com › 2020 › 08 › 02 › the-pearls-of-raku-issue-4-unit-sub-and-command-line-round-and-precision
The Pearls of Raku, Issue 4: unit sub MAIN and command line, round and precision – Andrew Shitov
If you convert the code to a function, you can use function’s signature to check the arguments for you. In the case of a simple script with the only function, use unit sub MAIN: unit sub MAIN(Int $a, Str $op where /<[-+*/]>/, Int $b); say (given $op { when '+' {$a + $b} when '-' {$a - $b} when '*' {$a * $b} when '/' {$a / $b} }) Also notice the difference in error reporting between these two programs. In the first case, an exception happens: $ raku calc1.raku 42 plus 3 Type check failed in assignment to $op; expected OpStr but got Str ("plus") in block <unit> at calc1.raku line 3