Exiting loops ahead of time

  1. Boolean logic
  2. Smarter scripts
  3. Multiple options

Often when we’re testing we don’t really want to see everything, we just want to see that it worked. The first several results will let us know that. Let’s put in a switch to limit the number of results to a specified maximum. We’ll call this switch limit and it will be followed by a number.

} elsif ($switch eq "limit") {
$limit = shift;
if ($limit !~ /^[1-9][0-9]*$/) {
print "\nYou must limit to a number, such as '33' or '2'.\n\n";
help();
exit;
}
}

First, we assign the result of the shift to a variable—our $limit variable. The next item on the command line after --limit should be the number of lines we want to limit to. Just to make sure, we check:

if ($limit !~ /^[1-9][0-9]*$/) {

This is a different form of regular expression. Instead of “=~” it is “!~”. This will match if the regular expression doesn’t match the text on the left. Remember, an exclamation point often stands in for the word not in Perl. Other than that, this regular expression is the same as any other.

We’ve already met the caret. When it is at the beginning of a regular expression, it matches the beginning of the text. The dollar sign, when it appears at the end of a regular expression, matches the end of the text. Square brackets match a list or range of characters. Here we’re using them to match a range. The first character must be a digit from 1 to 9. The second character must be a digit from 0 to 9. Normally, this would mean that the limit would have to be 10 to 19. However, immediately following the “[0-9]” there is an asterisk. The asterisk is just like the plus symbol in regular expressions except that it matches zero or more occurrences of the preceding piece of text instead of one or more.

Since the preceding character is any digit from 0 to 9, the combination of “[0-9]” and an asterisk matches zero or more digits. Matches would include 100, 1, 9, 19, 55, 637. Non-matches would include 01, 99X, Buffalo99. Any text that includes non-numbers or that begins with a zero will not match.

If the text following the --limit switch isn’t a number, the script warns them that it needs a number there, calls the help subroutine, and exits.

So, that’s a little bit more complicated of a switch. How do we handle implementing it?

Replace the line that prints the song information with:

#print the information if this line is one we want
if ($matched) {
$matches++;
print "$song ($album, by $artist)\n";
}
last if $limit && $matches >= $limit;

We’ve moved the if off of the print line and instead created an if block. We have Perl perform this block if $matched has something in it, that is, if it is true. If we have a match, the first thing we do is increment the variable $matches by 1. That’s what the “++” does. When “++” follows a variable, Perl will add one to that variable. If the variable doesn’t exist, or if it is not a number, Perl assumes it is 0 and sets it to 1.

Thus, $matches will count up the number of matches we have hit so far.

Outside of the if block, we have a new command: last. The last command exits the current loop, even if the loop wouldn’t otherwise be finished.

We have an if following the last command, however, so the last only gets performed if “$limit && $matches >= $limit”.

In other words, if $limit has something in it AND if $matches is greater than or equal to $limit.

If $limit doesn’t have anything in it—if we didn’t specify a limit—the last never gets performed. If $limit does have something in it, the last will get performed if $matches ever equals or exceeds the limit we specified on the command line.

Remember to add the help line:

print "\t--limit x: limit to x results\n";

You can now do searches and limit the results. Try the non-best-of search again, with a limit of 10:

./show --reverse --limit 10 best songs.txt

./show --reverse --limit 12 aerosmith songs.txt

And the screen no longer fills up with the thousands of non-matching songs.

  1. Boolean logic
  2. Smarter scripts
  3. Multiple options