If you're coming to Perl 6 from Perl 5, the global variable @*ARGS will be familiar to you as the place to get the command-line arguments to your program:

$ cat main1.pl6 #!/usr/bin/env perl6 put "ARGS = ", @*ARGS.join(', ');

$ ./main1.pl6 foo bar baz

ARGS = foo, bar, baz



The @ is the sigil that denotes the variable as an array, and the * is the "twigle" that denotes that the variable is a global. If you follow the above link to the documentation, you'll find a whole host of other dynamic and environmental variables like user, hostname, PID, cwd, etc.

Dealing directly with @*ARGS is fine your program accepts a few positional arguments where the first argument means one thing (name), the second argument another thing (rank), the third another (serial number), etc:

$ cat main2.pl6 #!/usr/bin/env perl6 my ($name, $rank, $serial-num) = @*ARGS;

put "name ($name) rank ($rank) serial number ($serial-num)";

$ ./main2.pl6 Patch Private 1656401

name (Patch) rank (Private) serial number (1656401)



Or if all the arguments are homogenous (e.g., a list of files to process), this works reasonably well:

$ cat main3.pl6 #!/usr/bin/env perl6 for @*ARGS -> $file {

put "Processing '$file'";

} put "Done."

$ ./main3.pl6 foo bar baz

Processing 'foo'

Processing 'bar'

Processing 'baz'

Done.



If we declare a MAIN subroutine, we can automatically assign the variables instead of taking them from @*ARGS :

sub MAIN ($name, $rank, $serial-num) { put "name ($name) rank ($rank) serial number ($serial-num)"; }

Perl will enforce the number of arguments and generate help when supplied the wrong number or when requested:

$ ./main4.pl6 Patch Private Usage: ./main4.pl6 <name> <rank> <serial-num> $ ./main4.pl6 Patch Private 1656401 name (Patch) rank (Private) serial number (1656401) $ ./main4.pl6 -h Usage: ./main4.pl6 <name> <rank> <serial-num>

You can also add type constraints:

$ cat main5.pl6 #!/usr/bin/env perl6 sub MAIN (Str $name, Str $rank, Int $serial-num) {

put "name ($name) rank ($rank) serial number ($serial-num)";

}

$ ./main5.pl6 foo bar baz

Usage:

./main5.pl6 <name> <rank> <serial-num>

$ ./main5.pl6 foo bar 123

name (foo) rank (bar) serial number (123)



To make them named arguments, simply prefix with a : and then you can supply the arguments in any order:

$ cat main6.pl6 #!/usr/bin/env perl6 sub MAIN (Str :$name, Str :$rank, Int :$serial-num) {

put "name ($name) rank ($rank) serial number ($serial-num)";

}

$ ./main6.pl6 -h

Usage:

./main6.pl6 [--name=<Str>] [--rank=<Str>] [--serial-num=<Int>]

$ ./main6.pl6 --name=Patch --serial-num=1656401 --rank=Private

name (Patch) rank (Private) serial number (1656401)



There's a problem if I don't supply any arguments to this last version:

$ ./main6.pl6 Use of uninitialized value of type Str in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in sub MAIN at ./main6.pl6 line 3 Use of uninitialized value of type Str in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in sub MAIN at ./main6.pl6 line 3 Use of uninitialized value of type Int in string context. Methods .^name, .perl, .gist, or .say can be used to stringify it to something meaningful. in sub MAIN at ./main6.pl6 line 3 name () rank () serial number ()

Perl is complaining that it can't print uninitialized values. I didn't declare that any of the arguments are required -- which I can do by post-fixing the variables with ! -- nor did I provide defaults for those that are not -- which I can do with = :

$ cat main7.pl6 #!/usr/bin/env perl6 sub MAIN (Str :$name!, Str :$rank='NA', Int :$serial-num=0) {

put "name ($name) rank ($rank) serial number ($serial-num)";

}

$ ./main7.pl6

Usage:

./main7.pl6 --name=<Str> [--rank=<Str>] [--serial-num=<Int>]



The absence of [] around the --name indicates to the user that the argument is required, while --rank and --serial-num are optional:

$ ./main7.pl6 --name=Patch name (Patch) rank (NA) serial number (0) $ ./main7.pl6 --name=Patch --serial-num=1656401 --rank=Private name (Patch) rank (Private) serial number (1656401)

Even though Perl is checking the types (string, integer) for our arguments, it's not enforcing any validation on the value. We can add a where clause to ensure we only get a positive value for --serial-num :

$ cat main8.pl6 #!/usr/bin/env perl6 sub MAIN (

Str :$name!,

Str :$rank='NA',

Int :$serial-num where * > 0 = 1

) {

put "name ($name) rank ($rank) serial number ($serial-num)";

}

$ ./main8.pl6 --name=Patch --serial-num=-10

Usage:

./main8.pl6 --name=<Str> [--rank=<Str>] [--serial-num=<Int>]

$ ./main8.pl6 --name=Patch

name (Patch) rank (NA) serial number (1)



As it turns out, the built-in UInt type will work for ensuring positive, so maybe we would be better off ensuring that the serial number is of the correct length:

$ cat main9.pl6 #!/usr/bin/env perl6 sub MAIN (

Str :$name!,

Str :$rank='NA',

UInt :$serial-num where *.Str.chars == 7 = 1111111

) {

put "name ($name) rank ($rank) serial number ($serial-num)";

}

$ ./main9.pl6 --name=Patch --serial-num=12345

Usage:

./main9.pl6 --name=<Str> [--rank=<Str>] [--serial-num=<Int>]

$ ./main9.pl6 --name=Patch --serial-num=1234567

name (Patch) rank (NA) serial number (1234567)



Unfortunately the usage doesn't include information about the length, so we can override the default USAGE:

$ cat main10.pl6 #!/usr/bin/env perl6 sub MAIN (

Str :$name!,

Str :$rank='NA',

UInt :$serial-num where *.Str.chars == 7 = 1111111

) {

put "name ($name) rank ($rank) serial number ($serial-num)";

} sub USAGE {

printf "Usage:

%s --name=<Str> [--rank=<Str>] [--serial-num=<Int>]

",

$*PROGRAM.basename; put "Note: --serial-num must be 7 digits in length."

}

$ ./main10.pl6

Usage:

main10.pl6 --name=<Str> [--rank=<Str>] [--serial-num=<Int>]

Note: --serial-num must be 7 digits in length.



I can move the --serial-num code into a subset and further constrain --rank to a list of acceptable values: