列印匹配行之前的第 n 行、匹配行以及匹配行之後的第 n 行

列印匹配行之前的第 n 行、匹配行以及匹配行之後的第 n 行

我想列印匹配行之前的第 n 行、匹配行以及匹配行中的第 n 行,其中「n」大於 2。

這是我的資料檔案的範例(下面的行號不是資料的一部分,僅用於標識),我正在檔案中搜尋的模式是「blah」example.txt

$ cat example.txt 
 1. a
 2. b
 3. c
 4. d
 5. blah
 6. e
 7. f
 8. g
 9. h
 10. blah
 11. i
 12. f
 13. g
 14. h

我希望輸出為:

 1. b
 2. blah
 3. g
 4. f
 5. blah
 6. g

請推薦任何一款襯墊!

答案1

awk -vn=3 '/blah/{print l[NR%n];print;p[NR+n]};(NR in p);{l[NR%n]=$0}'

假設沒有重疊。如果存在重疊,則所有相關行都會列印,但可能會列印幾次,並且不一定會按照輸入中的順序列印。

為了避免這種情況,你可以這樣寫:

awk -vn=3 '/blah/{p[NR-n]p[NR]p[NR+n]};(NR-n in p){print l[NR%n]}
  {l[NR%n]=$0};END{for(i=NR-n+1;i<=NR;i++)if (i in p) print l[i%n]}'

在這樣的輸入上:

1
2
3
4
blah1
5
6
blah2
blah3
7
8
9
10

第一個給出:

2
blah1
blah1
blah2
blah2
5
blah3
8
9

而第二個會列印:

2
blah1
5
blah2
blah3
8
9

答案2

這是 perl 一行:

$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
  if ($lines[$i]=~/blah/){
    print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
 }' example.txt 
b
blah
g
f
blah
g

若要變更周圍線的數量,請變更$n=3;為所需數量的$n=N位置。N若要變更符合的模式,請變更if ($lines[$i]=~/blah/)if ($lines[$i]=~/PATTERN/)

如果數字實際上是檔案的一部分,您可以執行以下操作:

$ perl -ne '$n=3;push @lines,$_; END{for($i=0;$i<=$#lines;$i++){
      if ($lines[$i]=~/blah/){
        print $lines[$i-$n],$lines[$i],$lines[$i+$n]}}
     }' example.txt | perl -pne 's/\d+/$./'
1. b
2. blah
3. g
4. f
5. blah
6. g

答案3

這是與 @terdon 類似的答案,但它只在記憶體中保留 2n+1 相關行:

my $n = shift;
my $pattern = shift;
my @lines = ("\n") x (2*$n+1);
while (<>) {
    shift @lines;
    push @lines, $_;
    if ($lines[$n] =~ m/$pattern/) {
        print $lines[0], $lines[$n], $lines[-1];
    }
}

你會像這樣運行它:perl example.pl 3 blah example.txt

答案4

效率不是很高。使用 grep 取得行號,使用 sed 列印行號。

for n in `grep -n blah example.txt | sed -e s/:.*//`
do
    sed -n -e "$[$n-3]p" -e "$[$n]p" -e "$[$n+3]p" example.txt
done

結果是

 2. b
 5. blah
 8. g
 7. f
 10. blah
 13. g

如果這些數字中的任何一個最終超出範圍,它可能會失敗。

相關內容