I have two values "usb 1-3" and "address 20". Now I am trying to search a text file ( basically a log file) which has both of these words.
Now that file has many lines with these words as:
Apr 27 13:30:55 box2 kernel: usb 1-3: USB disconnect, address 20
and
Apr 27 13:25:43 box2 kernel: usb 1-3: new high speed USB device using ehci_hcd and address 20
Now my requirement is that: I want to get the line with the second-to-last occurrence of these two words and then next 16 lines after that. Like if there are 6 occurrences in file (6 lines with both of these words) then I need the line with the 5th occurrence and the next 16 lines after it. If there are 10 occurrences then I need the 9th occurrence and the next 16 lines.
currently I was using
egrep -A 20 'usb 1-3:.*address 20' filename | tail -16 > output.
but it gives me last occurrence. not second-to-last. please note that line should have Both Words and in same order (usb 1-3 first and address 20 later) Please tell me if my question isn't clear. Thanks in advance.
This requires two passes, but it should do the trick:
tail -n +`egrep -n 'usb 1-3:.*address 20' filename |
tac | sed -n '2s/:.*//p'` filename | head -17
You could use awk
or perl
to do it in one pass, but you'd need to manage some buffers. Note that it uses tac
, which is a reverse cat
. If you don't have it on your system, try to drop tail -r
in its place.
if you have GNU grep
grep -B 1 -A 15 'usb 1-3.*address 20' filename
One way using perl
:
use warnings;
use strict;
die qq[Usage: perl $0 <input-file>\n] unless @ARGV == 1;
my (@lines, $found);
## Reverse content and pipe output to perl.
open my $fh, q[-|], qq{tac $ARGV[0]} or die qq[Open error: $!\n];
## Read line by line.
while ( <$fh> ) {
## Remove trailing '\n'.
chomp;
## Use an array as a FIFO structure and save last 16 lines
## processed.
if ( @lines > 16 ) {
pop @lines;
}
unshift @lines, $_;
## Count how many lines matches at same time 'usb 1-3' and
## 'address 20'.
if ( m/usb\s1-3/ && m/address\s20/ ) {
++$found;
}
## In second one, print lines saved.
if ( ($found || 0) == 2 ) {
printf qq[%s\n], join qq[\n], @lines;
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.