[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: match across line using grep



>> On Mon, 02 Aug 2010 14:56:45 +0800, 
>> Zhang Weiwu <zhangweiwu@realss.com> said:

Z> I'm grepping a bunch of files each have a segment code that executes a
Z> SQL.  My problem is that the query spans across several lines and I
Z> can't seem to make grep honor (?s) for that.

   Perl Is Our Friend.  Here's some text to search:

      me% cat -n sample
           1  Message-ID: <4C566C2D.7000206@realss.com>
           2  Date: Mon, 02 Aug 2010 14:56:45 +0800
           3  From: Zhang Weiwu <zhangweiwu@realss.com>
           4  Organization: Real Softservice
           5  Status: RO
           6  Content-Length: 2410
           7  Lines: 80
           8  
           9  I'm grepping a bunch of files each have a segment code
          10  that executes a SQL.  Both selects should match:
          11  
          12      select * from table1 where id=1;
          13  
          14      select * from table2 where id=1
          15      and name='foo'";
          16  
          17  I tried to use -z parameter for grep, which the manual says
          18  would make grep not treating \n as line terminator.  But
          19  it doesn't work neither.  A simple test shows I might have
          20  misunderstood the use of -z:

   The script below my signature gives these results:

      me% ./pgrep 'select.*from.*;' sample
      [sample:12]     select * from table1 where id=1;
                      matched >>select * from table1 where id=1;<<
      
      [sample:15]     select * from table2 where id=1
          and name='foo'";
                      matched >>select * from table2 where id=1
          and name='foo'";<<

   "[sample:15]" means the match happened at or before line 15 in file
   "sample".  You can pass multiple files on the command line.  The
   "matched" stuff is there in case there's some distracting text on the
   line besides the select statement.  If you want matching to be
   case-sensitive, change "si:" to "s:" on the line where $pattern is set.

-- 
Karl Vogel                      I don't speak for the USAF or my company

---------------------------------------------------------------------------
#!/usr/bin/perl -w
# Taken from perl-grep3.pl in "Mastering Perl"

use strict;

# Get the desired pattern, make newlines match '.' and ignore case.
my $pattern = shift @ARGV || die "I need a pattern\n";
$pattern = '(?si:' . $pattern . ')';

# Make sure pattern works.
my $regex = eval { qr/$pattern/ };
die "Check your pattern! $@" if $@;

# Use paragraph mode to handle newlines.
$/ = "";
my $line = 0;

while (<>) {
    $line += tr/\n/\n/;
    chomp;
    print "[$ARGV:", $line-1, "] $_\n\t\tmatched >>$&<<\n\n" if m/$regex/;
    $line = 0 if eof(ARGV);    # reset counter for a new file.
}

exit(0);


Reply to: