-vをgrepし、一致後の次の行を除外する方法は?


14

grepの正規表現に一致する各行に対して2行を除外するにはどうすればよいですか?
これは私の最小限のテストです:

SomeTestAAAA
EndTest
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestAABC
EndTest
SomeTestACDF
EndTest

そして、明らかに私は、例えばgrep -vA 1 SomeTestAAうまくいかないことを試みました。

望ましい出力は次のとおりです。

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

grep -v 'SomeTextAA' | ユニック?
DarkHeart

回答:


14

あなたは使うことができgrep-P(PCRE):

grep -P -A 1 'SomeTest(?!AA)' file.txt

(?!AA)はゼロ幅の負の先読みパターンで、AAafter がないことを保証しSomeTestます。

テスト:

$ grep -P -A 1 'SomeTest(?!AA)' file.txt 
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

ドットのエスケープ文字は何ですか?Some.Test.AAが好きですか?
Behrooz

1
でドットをエスケープ@Behrooz \.そうgrep -P -A 1 'SomeTest\.(?!AA)' file.txtgrep -P -A 1 'SomeTest(?!\.AA)' file.txt
heemayl

これはこの特定のケースで機能しSomeTest*\nEndTestます。OPのサンプル行はペアになっているため、実際にはgrep一致するすべての行にping を行いますSomeTest*SomeTestAA、一致後の1行のコンテキストではありません。入力にさらにいくつかの行を追加し(たとえば、各行のfoobar後に行を追加EndTest)、もう一度試してください。
don_crissti

1
@don_crisstiそれは本当です、私はすでにそれを回避しました。
Behrooz

@Behrooz-どうやってそれを回避したかを教えてください。質問の下で私のコメントに答えてください。
-don_crissti

4

これは、任意の入力で機能するsedソリューション(-nつまり、自動印刷なし)です。

sed -n '/SomeTestAA/!p          # if line doesn't match, print it
: m                             # label m
//{                             # if line matches
$!{                             # and if it's not the last line
n                               # empty pattern space and read in the next line
b m                             # branch to label m (so n is repeated until a
}                               # line that's read in no longer matches) but
}                               # nothing is printed
' infile

のような入力で

SomeTestAAXX
SomeTestAAYY
+ one line
SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestAABC
+ another line
SomeTestTHREE
EndTest
SomeTestAA
+ yet another line

ランニング

sed -n -e '/SomeTestAA/!p;: m' -e '//{' -e '$!{' -e 'n;b m' -e '}' -e'}' infile

出力

SomeTestONE
Message body
EndTest
########
SomeTestTWO
something here
EndTest
SomeTestTHREE
EndTest

つまり、grep -A1 SomeTestAA infile選択する行を正確に削除します。

SomeTestAAXX
SomeTestAAYY
+ one line
--
SomeTestAABC
+ another line
--
SomeTestAA
+ yet another line

面白い。それが//合って/SomeTestAA/いることに気づかなかった。この場合、否定表現と一致すると思いました/SomeTestAA/!。(+1)
Peter.O

@ Peter.O-ありがとう!いいえ、仕様により、空のREは常に最後のコマンドで使用された最後のREと一致する必要があります。!一部ではないRE、それはだsedもの。
don_crissti

3

複数行のリージョンを単一のレコードとして見るもので、より良い運が得られるかもしれません。sgrep私はあまり使用していないものがあります。

また、awkもあり、入力レコードの区切り文字と出力レコードの区切り文字を好きなように設定できます。

pat="^SomeTestAA"
awk  'BEGIN{ RS=ORS="\nEndTest\n"} !/'"$pat/" foo

ほとんどのawkプログラムは一重引用符で囲まれてい$patますが、シェル変数を展開できるように、最後に二重引用符に変更します。


awk -vpat="^SomeTestAA" -vRS="\nEndTest\n" 'BEGIN{ ORS=RS } $0 !~ pat' file
Peter.O

3

1つのオプションは、perlのc互換性のあるregular expression を使用することですgrep

pcregrep -Mv 'SomeTestAA.*\n' file

このオプションを-M使用すると、パターンを複数行に一致させることができます。


1
@don_crissti両方の行が削除されます。OPの仕様はこのケースをカバーしていません。
-jimmij

OPのサンプルと質問がそのようなケースをカバーしていないことは非常に明白です、私はこれがどのように機能するのか知りたいだけです(pcreに精通していません)コンテキスト行も)、偶数の連続した行が一致すると、失敗します(コンテキスト行は削除されません)。
-don_crissti

(GNU)が(オプションgrepを介して-P)PCREをすでにサポートしている場合、使用する利点は何pcregrepですか?
アリエル

@arielf grep-Mオプションをサポートしていません。
-jimmij

1

標準を使用sed

$ sed '/SomeTestAA/{ N; d; }' file
SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest

sedスクリプトは、ラインによって入力ファイルの行を解析し、ラインパターンと一致したときSomeTestAA、2つのsed編集コマンドNd実行されます。このNコマンドは、入力の次の行をパターンスペース(sed編集可能なバッファー)に追加し、パターンスペースをd削除して次のサイクルを開始します。


0

GNU seddコマンドを使用して行を削除し、接頭辞を付け/pat/,+Nてパターンに一致する行と後続のN行を選択できます。一致する行の後の単一の後続行のみを削除する場合、N = 1の場合:

sed -e '/SomeTestAAAA/,+1d'

0

Below sedコマンドを試してみたところ、うまくいきました

コマンド

sed  '/SomeTestAA/,+1d' filename

出力

SomeTestABCD
EndTest
SomeTestDEFG
EndTest
SomeTestACDF
EndTest
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.