i have a huge log file name abc.log .i have to search for a pattern name "pattern",it may occur 1000 times in the log file,every time it finds the pattern it should display the 10 lines above the pattern.
I appericiate your help.
If I understand the problem and the solution from ennstate, then sed will be loaded up 1000 times. Here is an alternate solution. The attachment is a perl script, pvg (perl version of grep, very limited edition). Assuming that you have perl, this will do simple matching and it will also do the "-B n" behavior of GNU grep. This can then be called once to process the log file. (Get the attachment, rename it to "pvg", then run the test script.) Execute "./pvg -h" for a help page.
Here's a test script:
#!/bin/bash -
# @(#) s3 Demonstrate printing of text before a matched line.
echo "(Versions displayed with local utility \"version\")"
version >/dev/null 2>&1 && version =o $(_eat $0 $1)
P=./pvg
echo
echo " Input file data3:"
cat data3
echo
echo " Looking for d, normal search:"
$P d data3
echo
echo " Looking for d, print previous 2:"
$P -B 2 d data3
echo
echo " Looking for d, print previous 2, separator:"
$P -s ' ----- \n' -B 2 d data3
echo
echo " Looking for ask, print previous 100, quiet:"
$P -q -B 100 ask data3
exit 0
Producing:
% ./s3
(Versions displayed with local utility "version")
Linux 2.6.11-x1
GNU bash 2.05b.0
Input file data3:
1 Alabama AL
2 Alaska AK
3 Arizona AZ
4 Arkansas AR
5 California CA
6 Colorado CO
7 Connecticut CT
8 Delaware DE
9 District of Columbia DC
10 Florida FL
Looking for d, normal search:
6 Colorado CO
10 Florida FL
( Lines read: 10; hits: 2 )
Looking for d, print previous 2:
4 Arkansas AR
5 California CA
6 Colorado CO
8 Delaware DE
9 District of Columbia DC
10 Florida FL
( Lines read: 10; hits: 2 )
Looking for d, print previous 2, separator:
4 Arkansas AR
5 California CA
6 Colorado CO
-----
8 Delaware DE
9 District of Columbia DC
10 Florida FL
( Lines read: 10; hits: 2 )
Looking for ask, print previous 100, quiet:
1 Alabama AL
2 Alaska AK
It can be a lot of work to make sure that perl and friends are installed, but once it's done, then you can use it for many things. Most systems have it already available.
There is also cgrep at freshmeat.net: Project details for cgrep which has a wealth of features. You need to go through a compilation, but it was fairly painless.
If I was going to use perl I would just use Tie::File, then you can treat the file like an array and use array subscripting to backtrack 10 lines. But he seems to want a shell script so I can't help with that unless calling a perl script is OK.
I looked over the reference, and added the sequence qw( -no_match_vars ) to my template. The warning is about a degradation in RE matching specifically. I added it to the short code I posted and it didn't seem to make a noticeable difference in a quick test (2 lines matched from the US Constitution from about 1000 lines). On the other hand, it's an easy thing to add.
Thanks for making me aware of that. Damian Conway does mention that in Perl Best Practices, but I haven't implemented all of that yet ... cheers, drl
I think perl would be good for this, it certainly should be easy. Tie::File is good for working with large files since it does not read them into memory, but it does alter the original file so you have to make sure to open the file in readonly mode. A preliminary script:
#!/usr/bin/perl
use strict;
use warnings;
use Tie::File;
use Fcntl 'O_RDONLY';
tie my @file, 'Tie::File', 'path/to/file', mode => O_RDONLY
or die "Can't open path/to/file: $!";
foreach my $i (10 .. $#file) {
if ($file[$i] =~ /pattern/) {
print qq{"pattern" found on line },$i+1,"$/";
print qq{previous ten lines:$/};
print map{"$_$/"} @file[$i-10 .. $i-1], "----------------------------";
}
}
I am not sure how efficient/ineffiecient this is though.
gnu grep has the -B option ( lines before ) and a -A option ( lines after ) as well. You may find this on your box as ggrep or something like that, otherwise you could certainly get the gnu grep out here somewhere: Installing GCC: Binaries - GNU Project - Free Software Foundation (FSF)
Here is the code to print the number of lines below your search... you can change the variable $lines to be how many lines you want to print after the word total.
Hope this helps!
#!/usr/bin/perl
$lines = 10;
$x = $lines;
open(F, "file.txt") or die "cannot read file";
while(<F>) {
chomp;
$my_line = "$_";
if ("$x" < "$lines") {
print "$my_line\n";
$x++;
}
if ("$my_line" =~ "total") {
$x = 0;
}
};
I know sethcoop is trying to help but his perl code is not well written, here is what you want to do:
#!/usr/bin/perl
use strict;
use warnings;
my $lines = 10;
open(F, "file.txt") or die "cannot read file";
while(<F>) {
if (/total/) {
print scalar <F> for (1..$lines);
last;
}
}
close(F);
Couple of things. If you need to find "total" more than once, remove the "last" command" otherwise it quits after the first match. If "total" is not a substring of another word add the \b anchor to the regexp so you don't get any false substring matches for words like "totals" instead of just "total".
if (/\btotal\b/) {
add "i" to the regexp to make it case-insensitive if necessary so "TOTAL" and "total" will match: