获取linux中第二次出现的单词

时间:2012-04-27 21:41:13

标签: linux bash grep

我有两个值“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) 如果我的问题不明确,请告诉我。提前谢谢。

3 个答案:

答案 0 :(得分:4)

这需要两次通过,但应该可以解决这个问题:

tail -n +`egrep -n 'usb 1-3:.*address 20' filename |
  tac | sed -n '2s/:.*//p'` filename | head -17

您可以使用awkperl一次性完成此操作,但您需要管理一些缓冲区。请注意,它使用tac,这是反向cat。如果您的系统上没有它,请尝试将tail -r放在其位置。

答案 1 :(得分:2)

如果你有GNU grep

grep -B 1 -A 15 'usb 1-3.*address 20' filename

http://manpages.debian.net/cgi-bin/man.cgi?query=grep

答案 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; 
    }   
}