Smart multiline grep?

Aaron Spiegel spiegela at gmail.com
Tue Jun 21 11:05:22 CDT 2005


I'm sure I've done this before with sed, but I can't find it.  I
thought I might challege my sed skills and whip it up, but I got lazy
and wrote it in perl (though I'm sure you could do this yourself if
you wanted).  Just make sure to escape your "start" and "end"
arguments for use in regexes.

Example: cgrep.pl -s 'some_function\(' -e '\);' -f ./some_source

Caveat:  Wouldn't work if you had wierd nesting, like:
   some_function( ... some_function( ... ); ... );
you'd just match:
   some_function( ... some_function( ... );

#!/usr/bin/perl -w

#Usage
# cgrep.pl -s <start pattern> -e <end pattern> -f <input file>

use strict;
use Getopt::Long;

my($start, $end, $file);

GetOptions(
    "start=s"   => \$start,
    "end=s"     => \$end,
    "file=s"    => \$file,
    );

die "All arguments are required" unless ($start && $end && $file);

if( defined( $file ) && -e $file )
{
    open( IN, $file ) || die "couldn't open file";
}

my @matches;
my $matching;
my $linecount = 0;

while( my $line = readline *IN)
{
    $linecount++;
    if( $line =~ /($start.*)/ )
    {   
        $matching = "true";
        push( @matches, $linecount . ": " . $1 . "\n" );

# in some cases our whole pattern will be in one line...
        if( $1 =~ /$end/){ $matching = "0"; }
        next;
    }

    if( $matching )
    {   
        if( $line =~ /(.*$end)/ )
        {   
            push( @matches, $linecount . ": " . $1 . "\n" );
            $matching = "0";
        }
        else
        {   
            push( @matches, $linecount . ": " . $line );
        }
    }
}

print @matches;


More information about the Kclug mailing list