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: