Tag Archives: parameters

Parsing Command Line Arguments in Perl 6

Like many people, I do a lot of automation using Perl. Years ago I began making utilities more generalized than specific, so I could re-use them in slightly different situations.

This means using a lot of command line arguments passed to Perl so that it knows what to do. Always in Perl 5 I used Getopt::Long to parse command line parameters – a truly great module that was always there. Not so with Perl 6 – some very good command line argument parsing is built in.

The MAIN Subroutine

The key is discovering that Perl 6 supports the use of a subroutine named “MAIN” which is called whenever you run a Perl 6 program, much like a C program. The command line arguments can be captured and processed in the definition of the MAIN subroutine.

For example, say you were writing a utility to crop an image. You want to be able to call it like

cropimage --top=10 --bottom=15 --left=50 --right=30 picture.png

In Perl 6, this is all you would need to do:

#!/usr/bin/env perl6

sub MAIN ( $filename,
           :$left, :$right,
           :$top,  :$bottom ) {

    say "$left $right $top $bottom $filename";
}

Variables get automatically defined in the MAIN scope, so you don’t have to use “my”. And if you put a colon “:” before the variable name, Perl will treat that as a named parameter. Notice how $filename doesn’t have a “:”? So we don’t have to put a named parameter in the command line.  But the other variables have “:”‘s before their names, so that means they have to be a named parameter.

Worth noting as well that Perl seems to like having the non-named parameters come before the named ones in the sub MAIN definition. In other words, positional ones come first, then do named ones.

Optional and Required Parameters

If you want to make a parameter required, shout it and put an “!” after it’s name. If you want it to be optional, put a “?” after it:

sub MAIN ( :$left!, :$right?,  ....

would mean that the named parameter –left MUST be supplied or Perl will generate an error for the user, while the –right parameter is optional.

Parameter Default Values

Now, with our example, we may not need all of the parameters every time, so they should be optional. But we will also want to have default values of 0, since when the parameters are not specified, we’ll want to crop 0 pixels off in that direction.

So lets make all of our parameters optional and with a default value of 0. Of course, parameters with default values are always optional. It’s just a matter of setting an equality in the MAIN definition:

#!/usr/bin/env perl6

sub MAIN ( $filename,
           :$left = 0, :$right  = 0,
           :$top  = 0, :$bottom = 0 ) {

    say "$left $right $top $bottom $filename";
}

With this, we’ll get actual 0’s coming out in our “say” 😉 even if we pass in no parameters but $filename.

Constraining Parameters into Sanity

You know there will always be some smart aleck or some universal happenstance that will throw wrenches at you. It’s the curse of being our own form of order within other’s entropy. Take for example the guy who wants to crop 10.88242 pixels in on the left. Yeah, that guy.

This is where Perl’s variable type system can help. There are LOTS of types available. We’ll keep this simple. In our case, we don’t want to slice up our pretty monitor’s pixels into .88242 segments. We want whole pixels or nothing! An integer, in other words.

To constrain parameters to a type, just place the type name before the variable/parameter definition. You don’t have to, of course, but if you choose to, it can help sometimes.

#!/usr/bin/env perl6

sub MAIN ( Str $filename,
           Int :$left = 0, Int :$right  = 0,
           Int :$top  = 0, Int :$bottom = 0 ) {

    say "$left $right $top $bottom $filename";
}

But you know they’ll be right back, breaking it again, because they thought it would be cute to crop a negative amount of pixels from the image. So maybe you’d want to use the UInt type instead (Unsigned Integer) so the value will have to always be positive.

Another useful thing is specifying a type Bool for a parameter variable, which basically makes it into a flag.

Oh, did I mention you can use dashes “-” in variable names in Perl 6? That amazed me, along with the fact you can use full UTF8 charactersets.

So suppose we wanted to be able to specify an optional output filename for our cropped image.  We’d like something like this to work:

cropimage --left=25 --output-file=cropped.png filename.png

All we have to do is call the named parameter variable $output-file and make it optional.

#!/usr/bin/env perl6

sub MAIN ( Str $filename,
           Int :$left = 0, Int :$right  = 0,
           Int :$top  = 0, Int :$bottom = 0,
           Str :$output-file? ) {

    say "$left $right $top $bottom $filename";

    say "Writing " ~ ($output-file || $filename);
}

Bonus Error Messages!

If you tried any of these and got an error, you’ll see how nicely Perl formats these when you’re using the built-in parameter handling. It’s an actual detailed “Usage:” description that is given to the end user, detailing all the parameters and their types. Very Cadillac. 🙂