web-dev-qa-db-ja.com

見つかった行の前/後の行X行を印刷する

特定のファイルで特定の文字列を検索したい。文字列が見つかった場合は、その行の前(または後)に行X行も印刷します。

これをgrepまたはawkで実行できますか、それとも組み合わせが必要ですか?

this のようなものが欲しいのですが、ヒットの前後のすべての後続/先行行ではなく、X番目だけです。

たとえば、私の入力が次のようになっているとします。

line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern
...

私は「パターン」という単語を検索し、その行+ 2行後の行を出力しますが、パターンの行の直後に続く行は出力しません。したがって、望ましい出力は次のとおりです。

line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern
...
7
MaVe

grepは、オプション-A(後)と-B(前)、および-C(コンテキスト)を使用してこれを行います。私がよく使用する例は次のとおりです。

   Sudo lspci -vnn | grep -i net -A 12

このコマンドは、一致後の12行を表示します。これには、ネットワーク(-i net)カードの制御に使用されるドライバーが含まれます。一般に、コマンドは次のとおりです。

  grep text_to_search -A n -B m file.extension

マッチの前にm行、マッチの後にn行を出力します。または使用できます

 grep text_to_search -C n file.extension

見つかったテキストを囲む合計n行を表示します(一致の前半分、一致後の半分)。

14
MariusMatutiae

この質問を少し調べた後、標準のGNUスクリプトを使用しないツールを使用して、実現可能性についてのコメントを修正する必要があると思います。これはvery特別なケースの。

あなたがawkを使うことを気にしないなら、私は次の解決策を提供することができます。このスクリプトcontext.awkは、まだ簡潔ではありません。

{
    lines[NR] = $0
    if (dump[NR]) {
        print $0;
    if ($0 ~ Pattern) {
        if (NR-Delta in lines) {
            print "---"
            print lines[NR-Delta]
        }
        dump[NR+Delta] = 1
        print $0;
    }
    if (NR-Delta in lines) 
        delete lines [NR-Delta];
}

次のように呼び出す必要があります。

awk -v Delta=X -v Pattern=PATTERN -f context.awk sample.txt

ここで、Xは目的の「コンテキスト距離」であり、PATTERNは検索パターンです。スクリプトは、---を間に挟んで行を出力することにより、ファイル内の複数のパターンコンテキストを分離しようとします。したがって、たとえば、次のsample.txt

line1
line2
line3 XXX
line4
line5
line6
line7 XXX
line8
line9
line10 XXX
line11

この呼び出しを使用して

awk -v Delta=3 -v Pattern=XXX -f context.awk sample.txt

次の出力を生成します

line3 XXX
line6
---
line4
line7 XXX
line10 XXX
---
line7 XXX
line10 XXX
3
Marcus Rickert

次のsedコマンドは、私がどのように表現するかを記述した場合に機能するようです。パターンに一致する行を印刷し、直後の行を印刷せず、パターンの2行後の行も印刷し、そのまま保持します。パターンマッチを検索します。

sed -n -e '/with a pattern/ {h;n;n;H;x;p}' file

少し見苦しいようですが、n(行をスキップして次の行に移動する)およびH(保留バッファーに追加してこの行を保持する)コマンドを追加することで、パターン一致後の任意の保持/スキップ関係。

一致に続いて、最初にhコマンドを使用して一致する行を保持バッファーにコピーすることに注意してください。最後に、ホールドとパターンスペースをxと入れ替え、パターンスペースをpと出力します。この時点で、sedはファイルを1行ずつ処理し続け、別の一致を探します。

sedコマンドの便利なリファレンスは here にあります。

2
deaks

grep -A2 <pattern> file | grep -B1 <pattern> | grep -v "\-\-"は私のために働きます:

user@box /tmp $ grep -A2 "with a pattern" test.txt | grep -B1 "with a pattern" | grep -v "\-\-"
line1 with a pattern
line3
line4 with a pattern
line6
line7 with a pattern

user@box /tmp $ cat test.txt 
line1 with a pattern
line2
line3
line4 with a pattern
line5
line6
line7 with a pattern
0
CHK