The internal grep function of Perl is a filter. You give it a list of values and a condition, and it returns a sublist of values that yield true for the given condition. It is a generalization of the grep or egrep commands we know from UNIX and Linux, but you don't need to know these commands in order to understand the grep of Perl.

The grep function takes two arguments. A block and a list of values.

For every element of the list, the value is assigned to $_, the default scalar variable of Perl, and then the block is executed. If the return value of the block is false, the value is discarded. If the block returned true the value from the list is kept as one of the return values.

Pay attention, there is no comma between the block and the second parameter!

Let's see a few examples for grep:

Filter out small numbers

my @numbers = qw(8 2 5 3 1 7);
my @big_numbers = grep { $_ > 4 } @numbers;
print "@big_numbers\n";      # (8, 5, 7)

This grep passes the values that are greater than 4, filtering out all the values that are not greater than 4.

Filter out the new files

my @files = glob "*.log";
my @old_files = grep { -M $_ > 365 } @files;
print join "\n", @old_files;

glob "*.log" will return all the files with a .log extension in the current directory.

-M $path_to_file returns the number of days passed since the file was last modified.

This example filters out the files that have been modified within the last year, and only let's through files that are at least one year old.

Is this element in the array?

Another interesting use of grep is to check if an element can be found in an array. For example, you have a list of names and you would like to know if the given name is in the list?

use strict;
use warnings;

my @names = qw(Foo Bar Baz);
my $visitor = <STDIN>;
chomp $visitor;
if (grep { $visitor eq $_ } @names) {
   print "Visitor $visitor is in the guest list\n";
} else {
   print "Visitor $visitor is NOT in the guest list\n";

In this case the grep function was placed in SCALAR context. In SCALAR context grep will return the number of elements that went through the filter. As we are checking if the $visitor equals to the current element this grep will return the number of times that happens.

If that's 0, the expression will evaluate to false, if it is any positive number then it will evaluate to true.

This solution works, but because it depends on the context it might be unclear to some people. Let's see another solution using the any function of the List::MoreUtils module.

Do any of the elements match?

The any function has the same syntax as grep, accepting a block and a list of values, but it only returns true or false. True, if the block gives true for any of the values. False if none of them match. It also short circuits so on large lists this can be a lot faster.

use List::MoreUtils qw(any);
if (any { $visitor eq $_ } @names) {
   print "Visitor $visitor is in the guest list\n";
} else {
   print "Visitor $visitor is NOT in the guest list\n";

UNIX grep and Linux grep?

Just to make the explanation round:

I mentioned that the build in grep function of Perl is a generalization of the UNIX grep command.

The UNIX grep filters the lines of a file based on a regular expression.

Perl's grep can filter any list of value based on any condition.

This Perl code implements a basic version of the UNIX grep:

my $regex = shift;
print grep { $_ =~ /$regex/ } <>;

The first line gets the first argument from the command line which should be a regular expression. The rest of the command line arguments should be filenames.

The diamond operator <> fetches all the rows from all the files on the command line. The grep filters them according to the regular expression. The ones that pass the filtering are printed.

grep on Windows

Windows does not come with a grep utility but you can install one or you can use the same Perl script as above.