grepを使用して一致する行の上または下にN行とM行を印刷する方法は?

grepを使用して一致する行の上または下にN行とM行を印刷する方法は?

次の内容(前行番号なし)を含むよく構成されたテキストファイルがあるとします。

 1 Mon Jun 9 00:11:47 CST 2014
 2 eth0      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:0E
 3           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
 4           inet6 addr: fe80::d6be:d9ff:fef5:5c0e/64 Scope:Link
 5           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
 6           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
 7           TX packets:250825 errors:0 dropped:0 overruns:0 carrier:0
 8           collisions:0 txqueuelen:10000
 9           RX bytes:365792552 (348.8 MiB)  TX bytes:20648578 (19.6 MiB)
10           Interrupt:24 Memory:d6000000-d6012100
11 Tue Jun 10 05:11:47 CST 2014
12 eth1      Link encap:Ethernet  HWaddr D4:BE:D9:F5:5C:10
13           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
14           inet6 addr: fe80::d6be:d9ff:fef5:5c10/64 Scope:Link
15           UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
16           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0
17           TX packets:1206000723 errors:0 dropped:0 overruns:0 carrier:0
18           collisions:0 txqueuelen:10000
19           RX bytes:1596108082 (1.4 GiB)  TX bytes:2960952707 (2.7 GiB)
20           Interrupt:25 Memory:d8000000-d8012100

ここで必要なのは、grepキーワード「eth」を使用して、eth0部分の行1、#3、#6、およびeth1部分の行#11、#13、#16をフィルタリングすることです。

Mon Jun 9 00:11:47 CST 2014    
inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

どうすればいいですか?

答え1

これは私にとって効果的です。

sed -n '/eth/{n;p;n;n;n;p;}' file
  • 検索文字列eth
  • n;:行をスキップ、p;:行を印刷する
  • n;n;n;:3行スキップして再印刷

編集する:

上の行、後の行、その後の3行が印刷されます。

sed -n -e '/eth/{x;1!p;g;$!n;p;n;n;n;p;D;}' -e h file

2番目の質問:おそらくコマンドを20回入力しないようですn;

答え2

このawkコマンドを試してください。

$ awk '$1~/^eth/ {getline; print; getline; getline; getline; print}' file
          inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
          RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
          inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
          RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

修正する:

$ awk '$1~/^eth/ {print previous; getline; print; getline; getline; getline; print}{previous=$0}' file
Mon Jun 9 00:11:47 CST 2014
           inet addr:10.179.113.125  Bcast:10.179.113.127  Mask:255.255.255.248
           RX packets:1169385 errors:0 dropped:0 overruns:0 frame:0
Tue Jun 10 05:11:47 CST 2014
           inet addr:10.254.4.1  Bcast:10.254.4.255  Mask:255.255.255.0
           RX packets:3806158038 errors:0 dropped:23193484 overruns:0 frame:0

答え3

以下は、印刷する行を選択するためのより柔軟性を提供するPerlを使用する別のアプローチです。

perl -n00E '
    @eth_records= grep {/eth/} split/(?=>Mon|Tue|Wed|Thu|Fri|Sat|Sun)/;
    @lines_to_print = qw{1 3 6};
    map { $_-- } @lines_to_print;
    $sep = "-"x80;
    for(@eth_records){
        say $sep;
        say for (split/\n/)[ @lines_to_print ];
        say $sep
    }' your_file

これにより、ファイルが日付名で始まる行に分割され、一致するすべての履歴の行1、3、6が印刷されます。/eth/

ファイル全体がメモリにロードされるため、ファイルが大きい場合は使用しないでください。

答え4

いくつかの提案があります:

  • grep

    grep -P 'CST|inet |RX p' file
    

    CSTinetこれにより、空白またはが含まれているか、それに続くすべての行が印刷されますRX pa。 Perl準拠の正規表現を有効にすることで、論理OR-Pとして使用できます。|次のいずれかの方法を使用して同じ目標を達成することもできます。

    grep -E 'CST|inet |RX p' file
    

    または

    grep  'CST\|inet \|RX p' file
    
  • sed

    sed -n '/CST\|inet \|RX p/p' file
    sed -rn '/CST|inet |RX p/p' file
    

    上記のように、-nすべての行印刷を抑制し、//pパターンに一致する行を印刷します。

  • perl

    Perlでも同じアプローチを使用できます。

     perl -ne 'print if /CST|inet |RX p/' file
    

    または、次のことを行うこともできます。

     perl -ne '$k=1 if /CST/; print if $k==1||$k==3||$k==6; $k++' file
    

    ここでは$k、行が一致すると変数が 1 に設定され、CST各行を読み取った後 1 ずつインクリメントされます。$k行の値が1、3、または6の場合、行を印刷します。これはよりスケーラブルなアプローチです。

    別の方法は、印刷したい行番号を知っていると仮定して直接印刷することです($.現在の行番号)。

    perl -ne 'print if $.==1||$.==3||$.==6||$.==11||$.==13||$.==16' file
    

    またはもっと慣用的に言えば:

    perl -ne '@d=(1,3,6,11,13,16); print if $.~~@d' file
    

    最後に、ファイル全体をメモリにロードし、興味のある行だけを印刷することもできます。

    perl -e '@F=<>; print @F[0,2,5,10,12,15]' file
    
  • awk

    awkNR現在行番号がどこにあるかと同じ基本的なアプローチを使用できます。

    awk '/CST|inet |RX p/' file
    

    または

    awk '{if(/CST/){k=1} if(k==1||k==3||k==6){print} k++;}' file
    

    または

    awk 'NR==1||NR==3||NR==6||NR==11||NR==13||NR==16' file
    

関連情報