In this article, we will discuss the different ways for how to print a few lines before a pattern match in log files. You will do well to know how to print a few lines AFTER a pattern match.
Let us consider a sample file as below. The requirement is to print 2 lines before the pattern 'Linux':
$ cat file Unix AIX Solaris Linux SCO1. grep will do it for you if your grep is a GNU grep.
$ grep -B2 Linux file AIX Solaris LinuxThe option '-B' will give n lines before the pattern. Hence '-B2 Linux' gives 2 lines before the pattern 'Linux' including the line matching the pattern.
2. awk way:
$ awk '/Linux/{for(i=1;i<=x;)print a[i++];print} > {for(i=1;i<x;i++)a[i]=a[i+1];a[x]=$0;}' x=2 file AIX Solaris LinuxIn this, an array is used which will always contain 2 lines before the current pattern. Hence, when the pattern is matched, the array contents along with the current pattern is printed.
3. Perl way:
$ perl -ne 'push @arr,$_; shift @arr if(@arr>3); > /Linux/ and print @arr;' file AIX Solaris LinuxOn reading a line, the line is pushed into an array named "arr". As and when the array size goes beyond 3, an element is removed from the front. In this way, the array will always contain 3 lines including the current pattern. On encountering the pattern 'Linux', the array is printed.
4. sed and tail combination:
$ sed -n '1,/Linux/p' file | tail -3 AIX Solaris LinuxUsing sed, a range of lines can be read. sed reads from 1st line till the pattern 'Linux'. From this result, we print the last 3 lines which is nothing but the line containing the pattern and 2 lines before the pattern.
5. awk and sed combination:
$ x=`awk '/Linux/{print NR-2","NR}' file` $ sed -n "$x p" file AIX Solaris LinuxUsing awk, the line number range is retrieved using the pattern 'Linux'. NR gives the current line number which is the number of the line containing the pattern, NR-2 gives the gives the number of the line which is 2 lines before. Using this line range in sed, the set of lines can be filtered.
6. Another awk way, only if the file is a small one:
$ awk '{a[++i]=$0;}/Linux/{for(j=NR-2;j<=NR;j++)print a[j];}' file AIX Solaris LinuxIn this, awk stores the entire file in memory using an array. On encountering the pattern 'Linux', it starts printing from 2 lines before using the for loop. Since awk stores the entire file in memory, this SHOULD not be used in case of large files since it will cause performance issues.
7. tac command (The least favored option)
$ tac file | grep -A2 Linux | tac AIX Solaris Linuxtac command is reverse of cat command which prints the file in reverse order. On the reversed file, grep for 2 lines above the pattern, and again reverse the output and display. This is just an option, not the preferred one due to its performance. tac command itself is not good for performance, add to that, using it twice.
Note: tac command is not available in all flavors of Unix.
Quite useful. On grep you can also use -Context to print lines around matching. I have discussed this on my post 10 example of grep command in Unix you may find useful.
ReplyDeleteJavin