Question

I am developing a small utility script in Perl, primarily to learn the language. The script has a main function acting as an action dispatcher and lot of small action routines performing one specific task each (like printing today's Day of year, counting files with age more than 7 days etc). The user would invoke the script using syntaxes like "./myscript doy", "./myscript doy 01/01/2013", "./myscript ls /home/test gt 7 days" etc. In general it is "./myscript action [mix of params & keywords]". Keywords can be "less than", "greater than" etc. The target action can be different even if the keyword changes (rather than doing if..else based on keywords in a parent action). The objective is to keep the script extensible (for myself and others) by adding an entry into the dispatch table and writing a small action.

The dispatch table is a hash as follows

my %Actions =
(   # Syntax => [RegEx, Description, Function]
    'help' => ['help', 'Displays this help', \&PrintHelp],
    'doy' => ['doy', 'Day of Year', \&DayOfYear],
    'doy <dd/mm/yyyy>' => ['doy (\d{2}/\d{2}/\d{4})', 'Day of Year for a date', \&DayOfYearForDate]
)

Key of the hash is the command syntax itself (shown to the user as part of help, along with the description). The RegEx is used to compare against the command line arguments (joined) to decide the action requested.

Now, to reduce the burden on the action routines, I would like to create an array of parameters as well in the main function and pass this as an argument to the action routine. So a command line like "./myscript ls /home/test gt 7 days" would result in @args = ['/home/test', 7]. The problem is that I could not figure out a way to identify the number of valid back references ($1, $2, ...) to be inserted into @args. Ofcourse I know the expected param count per action, but the intention is to keep it generic. One option I found was to check a range (1..10) like "if (defined ${$i})". This, when used in loop doesn't work with "use strict" option. Please suggest if there is a better method to capture the matching params and pass them to the action.

Was it helpful?

Solution

A backreference is a regex instruction to match something previously captured (e.g. \1). You actually want the number of captures ((...)).

Since a regex match returns what it captures in list context, you just need to count those

my @captures = $str =~ /.../;
my $count = @captures;

or

my $count = my @captures = $str =~ /.../;

or

my $count = () = $str =~ /.../;

You could also check @-.

my $count = /.../ ? $#- : undef;
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top