一致と前の行を除くすべてをgrepする方法

一致と前の行を除くすべてをgrepする方法

grepが一致しないようにしたいテキストファイルとパターンがあります。問題は、前の行も一致しないようにしたいということです。

私のファイル:

line 1
line 2
pattern
line 4

私はそれを試しました、cat file | grep -v pattern結果は次のようになります。

line 1
line 2
line 4

それから試してみましたが、cat file | grep -B 1 pattern結果は次のとおりです。

line 2
pattern

ただし、一緒に使用すると、次のような結果がcat file | grep -v -B 1 pattern得られます。

line 2

出力をどのように作成できますか?

line 1
line 4

答え1

私はgrepファイルから1行を抽出するときにのみこのツールを使用する傾向があるため、テキストでより複雑な編集を実行する必要がある場合は別のツールを使用します。

ここのすべての解決策は、パターンがテキスト内で複数回表示されることを前提としており、パターンが発生する行と直前の行を削除します。最初の2つの解決策は、パターンが連続した行で一致する場合に問題が発生します。


sedパターンを一致させ、/pattern/コマンドNとをトリガーすることができますd。このコマンドは、次の行をバッファに追加し、両方を削除します。

sed '/pattern/ { N; d; }' file

なぜなら、あなたはその行を捨てたいからです今後パターンを一致させるためにデータを逆に入力しますsed。最後の行から始めてファイルの先頭に移動します。sed完了したら、データを再び反転します。

tac file | sed '/pattern/ { N; d; }' | tac

このtacユーティリティはGNU coreutilsの一部です。ほとんどの非GNUシステムをtail -r代わりに使用できますtactail(1)マニュアルを確認してください)。

パターンが 2 つの連続した行と一致する場合、最初の行が削除されるため、最初の行より前の行は削除されません。


edエディタを使用してください。

printf '%s\n' 'g/pattern/ -1,. d' ,p Q | ed -s file

g/pattern/ -1,. dこれにより、ファイルの内容にコマンドが適用されます。このコマンドは、一致する各行を検索し、その行patternとその前の行を削除します。

最終,p編集Qコマンドは、ファイル全体を印刷して保存せずにエディタを終了します。

パターンが2つの連続した行と一致する場合は、最初の行の前の行を削除してから、2番目の行の前の行を削除します。

(最後の文は正しい文を書いてみると、きっとそのまま書く文章なのが明らかだ。 )


grep非標準ですが一般的に使用される-Bオプションを使用して、削除する必要がある行番号を指定することもできます。この数値は、sed生データで実行されるスクリプトに変換できます。

grep -n -B1 'pattern' file | sed 's/[:-].*/d/' | sed -f /dev/stdin file

grep質問のテキストに基づいてコマンドが出力されます。

2-line 2
3:pattern

...最初のsedコマンドはそれをsed編集コマンドに変換し、2dその後に3d(「2行と3行削除」)が続きます。sedパイプラインの最後のコマンドはこの編集スクリプトを取得し、元のテキストに適用します。

このバリアントは最初に削除する必要があるすべての行を見つけてから削除する2段階のアプローチを使用するため、パターンに一致する連続行の問題はありません(テキストを最初に読み取るときに行を削除する代わりに)。

答え2

tacでawkを使用すると、一致するパターンの前の行を好きなだけ削除できます。

$ tac file | awk '/pattern/{c=2} !(c&&c--)' file | tac
line 2
line 1

削除する行数(最大一致行まで)を変更してください。たとえば、数字97とその前の94行を削除c=2します。c=5

$ seq 100 | tac | awk '/97/{c=95} !(c&&c--)' | tac
1
2
98
99
100

それでは、awkの代わりにsedを試してみてください:-)。

バラより印刷には sed- または awk-a-line-follow-a-matching-pattern を使用します。これと他の関連イディオムの説明です。

答え3

メモ:fileこのコードは、出力と一致する各行に重複した行または部分文字列がない場合にのみ機能しますgrep -B1 pattern file

たとえば、file次の行を含む場合:

line 1
line 2
line 2
pattern
line 1 line 2
line 3

そして私が使用する出力はgrep -B1 pattern file | grep -v "$(cat)" fileあなたが期待するものとは異なります。

line 1
line 3

この問題を解決するための最良の方法は、次を使用することです。コサロナンダの答え

解決策(上記のように、重複した行または部分文字列がない場合にのみ機能します)

これはbash私にとって効果的です(より良い方法があると思います)。

grep -B1 pattern file | grep -v "$(cat)" file

zsh上記のコマンドには影響はありません。理由はわかりません。ただし、次のものを使用できます。

grep -B1 pattern file | { val="$(cat)" ; grep -v "$val" file; }

ポリスチレンcat your_file | grep pattern重複するので使用する必要はありません。使用する必要がありますgrep pattern your_file

答え4

pcregrepUltilineモードを使用できますM

pcregrep -Mv '\n.*pattern'

最初の行がパターンと一致すると、削除されません。この問題は、以下を使用して解決できます。

pcregrep -Mv '(\n)?.*pattern'

(...)この部分は\n明らかに必要ですが、バージョン8.39ではなぜ機能しないのかわかりません\n?.*pattern。)[\n]?.*pattern

関連情報