Created
October 13, 2014 03:06
-
-
Save StrikeW/78cb9246582171a5e798 to your computer and use it in GitHub Desktop.
Search a file for text. Like grep, but prints a window
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl -w | |
# | |
# search - Search a file for text. Like grep, but prints a window. | |
# Perl, Unix/Linux/Windows... | |
# | |
# 23-Jan-2006, ver 1.20 | |
# | |
# USAGE: search [-hinBI][-s num] pattern [files ...] | |
# | |
# -h # usage help | |
# -i # ignore case | |
# -n # print line numbers | |
# -B # don't print borders | |
# -I # don't invert match background | |
# -s num # number of surrounding lines | |
# eg, | |
# search fred msg.txt # find "fred" in the file "msg.txt". | |
# search -i fred msg.txt # case insensitive: "fred", "Fred"... | |
# search -n fred msg.txt # print line numbers. | |
# search -s3 fred msg.txt # print 3 surrounding lines. | |
# search fred file1 file2 # find "fred" in multiple files. | |
# cmd | search fred # search for "fred" in command output. | |
# | |
# Search is similiar to grep, however prints the surrounding two lines when | |
# it finds matches. This is similar to the OpenVMS search command, or GNU's | |
# grep with the window option. Regular Expressions are supported. | |
# | |
# The "pattern" is the search term. If regular expressions are used, they | |
# are best kept in single forward quotes. | |
# | |
# Originally written in several lines, it was too difficult to follow. It | |
# has now been rewritten in a verbose and conventional Perl style. | |
# | |
# SEE ALSO: GNU grep | |
# | |
# COPYRIGHT: Copyright (c) 2006 Brendan Gregg. | |
# | |
# This program is free software; you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License | |
# as published by the Free Software Foundation; either version 2 | |
# of the License, or (at your option) any later version. | |
# | |
# This program is distributed in the hope that it will be useful, | |
# but WITHOUT ANY WARRANTY; without even the implied warranty of | |
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
# GNU General Public License for more details. | |
# | |
# You should have received a copy of the GNU General Public License | |
# along with this program; if not, write to the Free Software Foundation, | |
# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. | |
# | |
# (http://www.gnu.org/copyleft/gpl.html) | |
# | |
# 26-Jun-2003 Brendan Gregg Created this. | |
# 23-Jan-2006 " " Tweaked style. | |
use strict; | |
use Getopt::Long; | |
Getopt::Long::Configure ("bundling", "no_ignore_case"); | |
# | |
# Setup Variables | |
# | |
my @Files = (); # Files to print. | |
my @Buffer = (); # Contains lines that may be printed. | |
my $inv = `tput smso`; # Inverse ESC sequence. | |
my $off = `tput rmso`; # Reset ESC sequence. | |
my $state = "buffering"; # State of the main routine. | |
my $WINDOW = 2; # Defaults, ... | |
my $INVERSE = 1; | |
my $NUMBERS = 0; | |
my $BORDERS = 1; | |
my $IGNORECASE = 0; | |
my $linenum = 0; | |
my $border = 0; | |
my $print = 0; | |
my $file = ""; | |
# | |
# Parse Options | |
# | |
my %Options = ( | |
'noborders' => sub { $BORDERS = 0; }, | |
'noinverse' => sub { $INVERSE = 0; }, | |
'help' => sub { usage(); }, | |
'ignorecase' => \$IGNORECASE, | |
'numbers' => \$NUMBERS, | |
'size' => \$WINDOW, | |
); | |
GetOptions (\%Options, 'noborders|B', 'noinverse|I', 'help|h', | |
'ignorecase|i', 'numbers|n', 'size|s=i') or usage(); | |
my $word = shift; | |
usage() unless defined $word and $word ne ""; | |
while (my $file = shift) { | |
push @Files, $file; | |
} | |
# | |
# MAIN | |
# | |
if (@Files > 0) { | |
### search files | |
foreach $file (@Files) { | |
open IN, $file or die "ERROR: Can't open file, $file: $!\n"; | |
$linenum = 0; | |
while (my $line = <IN>) { | |
search_line($line); | |
} | |
close IN; | |
} | |
} | |
else { | |
### search STDIN | |
while (my $line = <STDIN>) { | |
search_line($line); | |
} | |
} | |
# search_line - searches a line for the input word. | |
# | |
# This is the main routine to search $line and print results. This is | |
# a shortcut to a lump of code rather than a regular subroutine (hense | |
# the usage of so many globals). | |
# | |
# Global flags used are $IGNORECASE, $NUMBERS, $BORDERS, $INVERSE, $WINDOW. | |
# Global vars used are @Buffer, $state, $print, $linenum, @Files, $file. | |
# | |
# This is a stateful subroutine, which can be followed by the $state var. | |
# This was set as a string for readability (not speed). | |
# | |
sub search_line { | |
my $line = shift; | |
my $junk; | |
### Check for a match | |
if ($IGNORECASE) { | |
$state = "found" if $line =~ /$word/i; | |
} | |
else { | |
$state = "found" if $line =~ /$word/; | |
} | |
### Add line numbers | |
if ($NUMBERS) { | |
$linenum++; | |
$line =~ s/^/$linenum:/; | |
} | |
### Add filename | |
if (@Files > 1) { | |
$line =~ s/^/$file:/; | |
} | |
### Found, match found, print lines and buffer | |
if ($state eq "found") { | |
if ($border && $BORDERS && (- $print > $WINDOW)) { | |
# The third term above solves a bug when sequential | |
# windows shouldn't have a border. | |
print "-----\n"; | |
$border = 0; | |
} | |
if ($INVERSE) { | |
if ($IGNORECASE) { | |
$line =~ s/($word)/$inv$1$off/ig; | |
} | |
else { | |
$line =~ s/($word)/$inv$1$off/g; | |
} | |
} | |
print @Buffer, $line; | |
@Buffer = (); | |
$print = $WINDOW; # print more lines. | |
$state = "printing"; | |
} | |
### Printing, keep printing lines from a previous match | |
elsif ($state eq "printing") { | |
print $line if $print; | |
$print--; | |
if ($print <= 0) { # no more lines to print. | |
$border = 1; # print border if needed. | |
$state = "buffering"; | |
} | |
} | |
### Buffering, buffer lines in case of a future match | |
elsif ($state eq "buffering") { | |
push @Buffer, $line; | |
$junk = shift @Buffer if @Buffer > $WINDOW; | |
$print--; # counter for a border check. | |
} | |
} | |
# usage - print the usage message and exit. | |
# | |
sub usage { | |
print STDERR qq/USAGE: search [-hinBI][-s num] pattern [files ...] | |
-h # usage help | |
-i # ignore case | |
-n # print line numbers | |
-B # don't print borders | |
-I # don't invert match background | |
-s num # number of surrounding lines | |
eg, | |
search fred msg.txt # find "fred" in the file "msg.txt". | |
search -i fred msg.txt # case insensitive: "fred", "Fred"... | |
search -n fred msg.txt # print line numbers. | |
search -s3 fred msg.txt # print 3 surrounding lines. | |
search fred file1 file2 # find "fred" in multiple files. | |
cmd | search fred # search for "fred" in output.\n/; | |
exit 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment