grepを使用してあるパターンを一致させ、他のパターンと一致させるために逆方向を実行する方法は?

grepを使用してあるパターンを一致させ、他のパターンと一致させるために逆方向を実行する方法は?

を使用して、grep特定のパターンと一致し、他のパターンと一致しないすべての行を選択したいと思います。オプション(または)をgrep使用できるように単一の呼び出しを使用したいと思います。--after-context--before-context--context

-vgrepそのオプションを使用するために渡すすべてのパターンを無効にするため、ここでは機能しません-e

はい

一致する行を検索し、一致needleする行を無視し、ignore meコンテキストの下に1行あります。

これは私の入力ファイルです。

one needle ignore me
two
three
four needle
five

私が望む出力は次のとおりです。

four needle
five

ご覧のとおり、この単純なソリューションは機能しません。

$ cat file | grep --after-context=1 needle | grep -v 'ignore me'
two
---
four needle
five

答え1

GNU grepがある場合は、次のものを使用できます。パール正規表現、その一つ否定的な構造

grep -A1 -P '^(?!.*ignore me).*needle'

GNU grepがない場合は、次のことができます。awkでコンテキストオプションをエミュレートします。

awk -v after=3 -v before=2 '
/needle/ && !/ignore me/ {
    for (i in h) {
        print h[i];
        delete h[i];
    }
    until = NR + after;
}
{
    if (NR <= until) print $0; else h[NR] = $0;
    delete h[NR-before];
}
END {exit !until}
'

答え2

GNUを使っているようです。。 GNU grepを使用すると、--perl-regex次の例のようにフラグを渡してPCREを有効にしてから、否定的な予測アサーションを提供できます。

grep --after-context=1 \
--perl-regex '^(?:(?!ignore me).)*needle(?:(?!ignore me).)*$' file.txt
four needle
five

ここで注目すべき主な事項は、(?:(?!STRING).)*そのままSTRINGという[^CHAR]*ことです。CHAR

答え3

複数行IOをよりよく処理するので、代わりにawkを使用することをお勧めします。誰でも1)結果を--\nレコード区切り記号としてGNU awkにパイプする2)awkですべての一致を実行します。

オプション1

<file grep -A1 needle | awk '!/ignore me/' RS='--\n' ORS='--\n'

出力:

four needle                                                                                  
five
--

このオプションは、レコード全体を検索ignore me、設定、およびFS=1一致させ、$1最初の行とのみ比較します。

オプション2

<file awk 'a-- > 0; $0 ~ re1 && $0 !~ re2 { print $0; a=after }' re1=needle re2='ignore me' after=1

関連情報