Skip to content

Commit 529d42b

Browse files
authored
grep: implement -A context option (#810)
* Show non-matching context lines after a matching line * A new match may occur within the context lines being displayed; this resets the context counter unless the match limit (-m value) was already reached * Display a line of "--" to indicate the end of the context block * If -A is used with -n, follow line number with '-' instead of ':' to indicate context lines * When -A is used with -m, terminate the search at the end of the context and not the exact line triggering match limit %perl grep -n -A 8 perl ar # test1: context bleeds into the line8 match 1:#!/usr/bin/perl 2- 3-=begin metadata 4- 5-Name: ar 6-Description: create and maintain library archives 7-Author: dkulp 8:License: perl 9- 10-=end metadata 11- 12-=cut 13- 14-use strict; 15- 16-use POSIX qw(strftime); -- %perl grep -n -A 8 -m 1 perl ar # test2: line8 match doesn't count due to -m1 limit 1:#!/usr/bin/perl 2- 3-=begin metadata 4- 5-Name: ar 6-Description: create and maintain library archives 7-Author: dkulp 8:License: perl 9- -- %perl grep -A 4 perl ar # test3: no -n #!/usr/bin/perl =begin metadata Name: ar -- License: perl =end metadata =cut --
1 parent 4932ef0 commit 529d42b

File tree

1 file changed

+40
-10
lines changed

1 file changed

+40
-10
lines changed

bin/grep

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ use File::Spec;
5454
use File::Temp qw();
5555
use Getopt::Std;
5656

57-
our $VERSION = '1.011';
57+
our $VERSION = '1.012';
5858

5959
$| = 1; # autoflush output
6060

@@ -88,7 +88,7 @@ sub VERSION_MESSAGE {
8888

8989
sub usage {
9090
die <<EOF;
91-
usage: $Me [-inCcwsxvHhLlFgurpaqT] [-e pattern] [-m NUM]
91+
usage: $Me [-inCcwsxvHhLlFgurpaqT] [-e pattern] [-A NUM] [-m NUM]
9292
[-f pattern-file] [-P sep] [pattern] [file...]
9393
9494
Options:
@@ -113,6 +113,7 @@ Options:
113113
-r recursive on directories or dot if none
114114
-p paragraph mode (default: line mode)
115115
-P ditto, but specify separator, e.g. -P '%%\\n'
116+
-A show lines after each matching line
116117
-a treat binary files as plain text files
117118
-s suppress errors for failed file and dir opens
118119
-T trace files as opened
@@ -248,11 +249,14 @@ sub parse_args {
248249
@ARGV = @tmparg;
249250

250251
$opt{'p'} = $opt{'P'} = ''; # argument to print()
251-
getopts('inCcwsxvHhe:f:LlgurpP:aqTFZm:', \%opt) or usage();
252+
getopts('inCcwsxvHhe:f:LlgurpP:aqTFZm:A:', \%opt) or usage();
252253

253254
if (defined $opt{'m'} && $opt{'m'} !~ m/\A[0-9]+\z/) {
254255
die "$Me: invalid max count\n";
255256
}
257+
if (defined $opt{'A'} && $opt{'A'} !~ m/\A[0-9]+\z/) {
258+
die "$Me: bad line count for -A\n";
259+
}
256260
$opt{'l'} = 0 if $opt{'L'};
257261
my $no_re = $opt{F} || ( $Me =~ /\bfgrep\b/ );
258262

@@ -454,23 +458,33 @@ FILE: while ( defined( $file = shift(@_) ) ) {
454458
}
455459

456460
$total = $Matches = 0;
461+
my $ctx_a = 0;
457462

458463
LINE: while (<$fh>) {
459464
if (defined $opt->{'m'}) { # maximum may be zero
460-
last LINE if $total >= $opt->{'m'};
465+
last LINE if $total >= $opt->{'m'} && $ctx_a == 0;
461466
}
462467
$Matches = 0;
463468

464469
##############
465470
&{$matcher}(); # do it! (check for matches)
466471
##############
467472

468-
next LINE unless $Matches;
473+
if ($ctx_a > 0) {
474+
$ctx_a--; # show context line
475+
} elsif (!$Matches) {
476+
next LINE;
477+
}
469478

470479
$total += $Matches;
471480
last FILE if $opt->{'q'}; # single match for all files
472481
last LINE if $opt->{'L'}; # one match is enough
473482

483+
if (defined $opt->{'A'} && $Matches) {
484+
unless (defined($opt->{'m'}) && $opt->{'m'} < $total) {
485+
$ctx_a = $opt->{'A'};
486+
}
487+
}
474488
if ( $opt->{p} || $opt->{P} ) {
475489
s/\n{2,}$/\n/ if $opt->{p};
476490
chomp if $opt->{P};
@@ -485,8 +499,21 @@ FILE: while ( defined( $file = shift(@_) ) ) {
485499
}
486500
unless ($opt->{'c'}) {
487501
print($name, ':') if $Mult;
488-
print $opt->{n} ? "$.:" : "", $_,
489-
( $opt->{p} || $opt->{P} ) && ( '-' x 20 ) . "\n";
502+
if ($opt->{'n'}) {
503+
print $.;
504+
if ($Matches) {
505+
print ':';
506+
} else {
507+
print '-';
508+
}
509+
}
510+
print $_;
511+
if ($opt->{'p'} || $opt->{'P'}) {
512+
print ('-' x 20), "\n";
513+
}
514+
}
515+
if ($ctx_a == 0 && !$Matches) {
516+
print "--\n";
490517
}
491518
}
492519
close $fh;
@@ -513,9 +540,8 @@ grep - search for regular expressions and print
513540
514541
=head1 SYNOPSIS
515542
516-
B<grep> [ B<-[incCwsxvhHlLFigurpaqT]> ] [ B<-e> I<pattern> ] [ B<-m> I<NUM> ]
517-
518-
[ B<-f> I<pattern-file> ] [ B<-P> I<sep> ] [ I<pattern> ] [ I<files> ... ]
543+
grep [-incCwsxvhHlLFigurpaqT] [-e pattern] [-A NUM] [-m NUM]
544+
[-f pattern-file] [-P sep] [pattern] [file ...]
519545
520546
=head1 DESCRIPTION
521547
@@ -541,6 +567,10 @@ The following options are accepted:
541567
542568
Display a maximum of NUM matches per file.
543569
570+
=item B<-A> I<NUM>
571+
572+
Display NUM lines of context after each matching line.
573+
544574
=item B<-a>
545575
546576
List matching lines from binary files as if they were plain text files.

0 commit comments

Comments
 (0)