我有两个值“usb 1-3”和“address 20”。现在我正在尝试搜索具有这两个词的文本文件(基本上是一个日志文件)。
现在该文件有许多行,其中包含以下单词:
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
现在我的要求是:我希望得到这两个单词倒数第二次出现的行,然后是接下来的16行。就像文件中有6个出现(这两个单词都有6行)那么我需要第5次出现的行和接下来的16行。如果有10次出现,那么我需要第9次出现和接下来的16行。
目前我正在使用
egrep -A 20 'usb 1-3:.*address 20' filename | tail -16 > output.
但它让我最后一次出现。不是倒数第二个。请注意,该行应该具有两个单词并且顺序相同(首先是usb 1-3,后面是地址20) 如果我的问题不明确,请告诉我。提前谢谢。
答案 0 :(得分:4)
这需要两次通过,但应该可以解决这个问题:
tail -n +`egrep -n 'usb 1-3:.*address 20' filename |
tac | sed -n '2s/:.*//p'` filename | head -17
您可以使用awk
或perl
一次性完成此操作,但您需要管理一些缓冲区。请注意,它使用tac
,这是反向cat
。如果您的系统上没有它,请尝试将tail -r
放在其位置。
答案 1 :(得分:2)
如果你有GNU grep
grep -B 1 -A 15 'usb 1-3.*address 20' filename
答案 2 :(得分:0)
使用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;
}
}