grep#
Filter a list to the elements where the block or expression is true.
grep walks LIST from left to right, evaluates BLOCK or EXPR
once per element with $_ aliased to that element, and returns the
elements for which the test produced a true value. It is a list
filter, not a loop — the list you get back is a subset of the list
you passed in, in original order.
Synopsis#
grep BLOCK LIST
grep EXPR, LIST
my @kept = grep { COND } @list;
my @match = grep /pattern/, @list;
The two forms are interchangeable in power; BLOCK is the general
case, and EXPR is a convenience for one-expression tests. When
EXPR is a bare regex (/.../, m/.../, or qr/.../), it is
implicitly matched against $_ — this is the idiom behind
grep /^#/, @lines.
What you get back#
List context: the filtered list, in original order, with each returned element an alias into the source list (see Global state and Edge cases).
Scalar context: the count of elements for which the test was true. Not a boolean — it is the size of what the list context would have produced, so
0is false, any positive count is true.
my @keep = grep { $_ > 0 } @nums; # list context: filtered list
my $count = grep { $_ > 0 } @nums; # scalar context: count
Global state it touches#
$_is aliased to each element ofLISTfor the duration of oneBLOCKorEXPRevaluation. On exit fromgrep,$_is restored to whatever it held before the call. Because the alias is to the real element — not a copy — assigning to$_inside the block mutates the source list in place. This is the same contract asmapand as aforloop’s index variable.The bare-regex form of
EXPRreads and writes all the usual match-related magic variables ($1..$9,$&,${^MATCH},@+,@-,%+,%-,pos) on each iteration, exactly as if you had written the match longhand.
Examples#
Filter out undefined values:
my @vals = (1, undef, 2, undef, 3);
my @defined = grep { defined $_ } @vals;
# @defined = (1, 2, 3)
Regex filter via the expression form — the bare regex matches
against $_:
my @lines = ("# comment", "code", "# another", "more code");
my @code = grep !/^#/, @lines; # drop comments
my @comments = grep /^#/, @lines; # keep comments
Custom test via the block form, when the condition is more than one expression:
my @users = (
{ name => "alice", active => 1, age => 30 },
{ name => "bob", active => 0, age => 25 },
{ name => "carol", active => 1, age => 17 },
);
my @adults_active = grep {
$_->{active} && $_->{age} >= 18
} @users;
Count without building the list — use scalar context:
my @errors = ("ok", "fail", "ok", "fail", "fail");
my $nfail = grep { $_ eq "fail" } @errors; # 3
if (grep { $_ eq "fail" } @errors) { # boolean use
warn "had failures";
}
Remove blank and whitespace-only lines:
my @clean = grep { /\S/ } @lines;
Filter the keys of a hash by some property of the value:
my %scores = (alice => 42, bob => 17, carol => 95);
my @passing = grep { $scores{$_} >= 50 } keys %scores;
Edge cases#
$_is an alias, not a copy. Modifying$_inside the block modifies the original list element. This is occasionally useful but more often a bug; write a read-only test:my @bumped = grep { $_++; $_ > 10 } @nums; # MUTATES @nums
If the elements are themselves not variables (e.g. literals, constants, or the result of a function call), assigning to
$_is a runtime error — “Modification of a read-only value”.Returned elements are aliases too. Elements of the returned list share storage with the source list, just like the index variable of a
forloop. Writing to them through the returned list propagates back:my @arr = (1, 2, 3, 4); my @even = grep { $_ % 2 == 0 } @arr; $even[0] = 99; # @arr is now (1, 99, 3, 4)
This is rarely wanted. Copy explicitly with
map { $_ } grep ...or a freshmywhen you need independent storage.Expression form vs. block form — precedence.
grep EXPR, LISTuses a comma to separate the test from the list;grep BLOCK LISTdoes not. Mixing them trips you up:grep /x/, @arr; # EXPR form, correct grep { /x/ } @arr; # BLOCK form, correct grep { /x/ }, @arr; # WRONG: comma after block is a syntax # error or silently wrong depending on # context
grepin chained expressions.greptakes aLIST, which means everything after the first argument is consumed as part of the list. Parenthesise when you want to followgrepwith more terms:my @out = (grep { /x/ } @a), @b; # concatenates filtered @a and @b my @bad = grep { /x/ } @a, @b; # filters BOTH @a and @b together
Not a loop.
grepis an expression, not a control structure.last,next, andredoinside the block target the nearest enclosing loop, not thegrepitself — they will exit or restart whateverfor/whilethegrepsits inside, not thegrep. Use an earlyreturnfrom a helper sub if you need to short-circuit, or switch toList::Utilfirstwhen all you want is the first match.Empty input is empty output.
grepover an empty list is an empty list in list context and0in scalar context. No special case needed.Hash flattening.
grep { ... } %hwalks the hash’s alternating key/value flattening; the block sees keys and values interleaved in$_. This is almost never what you want; filter the keys and rebuild instead:my %filtered = map { $_ => $h{$_} } grep { some_test($_, $h{$_}) } keys %h;
Differences from upstream#
Fully compatible with upstream Perl 5.42.
See also#
map— same iteration contract with the same$_alias semantics, but returns what the block produced for each element rather than the element itselfsort— reorder a list; often chained withgrepassort { ... } grep { ... } @listany/all— short-circuiting boolean tests over a list fromList::Util; use these instead ofscalar grepwhen you only need a yes/no answer and the list is large or the test is expensivefirst(fromList::Util) — return the first element matching a block and stop; the right tool whengrepis being used only to fetch one matchfor/foreach— the looping construct with the same$_aliasing rule; reach for it when you want side effects, not a filtered list$_— the default scalar thatgrepaliases on every iteration