跨行搜索脚本:mgrep

写了做跨行搜索的脚本,用Perl。我知道也可以在bash里用sed,但我认为用那的话灵活性就不如用Perl了,因为我还要给它扩展各种我需要的功能。

闲话少说,上代码!

[perl]

!/usr/bin/perl -w

From: http://www.kclug.org/pipermail/kclug/2005-June/028106.html

Hacked by WANG Cong.

Copyright (C) 2008, WANG Cong

Usage

mgrep.pl -s -e [—nonum]

use strict;
use warnings;
use Getopt::Long;

my($start, $end, $file);
my $num = 1;

my $allow_nest = 0;

my $allow_recursion = 0;
my $allow_binary = 0;

GetOptions(
“start=s” => $start,
“end=s” => $end,
“nonum” => sub { $num = 0; },
“recursion” => sub { $allow_recursion = 1 },
“binary” => sub { $allow_binary = 1 }

“nest” => sub { $allow_nest = 1; }

);

$file = shift;

die “$start and $end options are both required. And so is the file name.”
unless ($start && $end && $file);

my $start_reg = eval {qr/$start/};
die “The start pattern is not correct!” if $@;
my $end_reg = eval {qr/$end/};
die “The end pattern is not correct!” if $@;

## sub

sub mgrep_file
{
my @matches;

#my @nest_stack;
my $matching; #boolean
my $added = 0; #boolean
my $linecount = 0;
my $file = shift;

open( IN, $file ) or return undef;

while( my $line = readline *IN)
{
$linecount++;
if( $line =~ /($start_reg.*)/ )
{
    $matching = 1;
    if(!$added){
    push @matches, "==", $file, "==n";
    $added = 1;
    }
    if ($num) {
    push( @matches, $linecount . ": " . $1 . "n" );
    }else{
    push( @matches, $1 . "n" );
    }

    if( $1 =~ /$end_reg/){ $matching = 0; }
    next;
}

if( $matching )
{
    if( $line =~ /(.*$end_reg)/ )
    {
    if ($num){
        push( @matches, $linecount . ": " . $1 . "n" );
    }else{
        push( @matches, $1 . "n" );
    }
    $matching = 0;
    }
    else
    {
    if ($num){
        push( @matches, $linecount . ": " . $line );
    }else{
        push( @matches, $line);
    }
    }
}
}
close IN;
return @matches;

}

sub mgrep_dir
{
my $dir = shift;
my @file_list;
my @match_list = ();
my $ret;
my @lret;

opendir(IN_DIR, $dir) || return undef;
@file_list = grep { $_ ne '.' and $_ ne '..' } readdir IN_DIR;

if (@file_list){
for my $one (@file_list) {
    my $fname = "$dir/$one";
    if (-f $fname){
    next if(!-T $fname && !$allow_binary);
    $ret = mgrep_file($fname);
    next unless @$ret;
    push @match_list, @$ret;
    }
    if ($allow_recursion && -d $fname){
    @lret = mgrep_dir($fname);
    next unless @lret;
    push @match_list, @lret;
    }
}
}

closedir IN_DIR;
return @match_list;

}

##### main

while ($file)
{
my $ret;
my @list;

if (-f $file){
next if(!-T $file && !$allow_binary);
$ret = mgrep_file($file);
print @$ret;
}
elsif (-d $file){
@list = mgrep_dir($file);
print @list;
}else{
die "$file is not existed!";
}

$file = shift;

}

[/perl]