ファイル内のテキストをgrepし、そのテキストを含む段落を表示する方法は?


24

ファイル内のテキストは次のとおりです。

Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

「42B」をgrepして、上記のテキストから次のような出力を取得する必要があります。

Pseudo name=Apple
Code=42B
state=fault

grep/ awk/ を使用してこれを達成する方法について誰にもアイデアがありますsedか?


この質問に「grep」というタグを付けました。その場合、「grep」ソリューションのみを探していますか?質問では、awk&sedも指定します。これらのタグを追加できますか?昨夜質問を編集したとき、私はあなたの意図がわからなかった。
slm

回答:


38

awk

awk -v RS='' '/42B/' file

RS=入力レコードの区切り文字を改行から空白行に変更します。レコード内のいずれかのフィールドにレコードが含まれている場合/42B/

''(ヌル文字列)は、POSIXに従って空白行を表すために使用されるマジック値です。

場合RSがヌルである、その後レコードは、以下からなる配列によって分離され、<newline>加えて一つ以上の空白行、先頭または末尾の空白行は、入力の先頭または末尾に空のレコードをもたらさないもの、及び<newline>、常にフィールドセパレータでなければなりませんFSの価値に関係なく。

出力セパレーターは単一の改行のままなので、出力段落は分離されません。出力段落の間に空白行があることを確認するには、出力レコード区切り文字を2つの改行に設定します。

awk -v RS='' -v ORS='\n\n' '/42B/' file

1
+1はエレガントなソリューションです。ただし、ファイルをリダイレクトする必要はありません
...-jasonwryan

指はオートパイロットに乗っていました。
llua

2
@jasonwryanあなたがawkの内のファイル名へのアクセスを(必要な場合を除き、FILENAME)ファイル名のためにそのことを回避するのに問題が含有するものとして、それは使用のリダイレクトには悪い考えではありません=かで始まる-(またはもの-)、一貫性のあるエラーメッセージになり、そしてことを回避するには、実行中awkまたは実行入力ファイルを開けない場合は、他のリダイレクト。
ステファンシャゼル

14

データが常にその前後の行になるように構造化されていると仮定すると、grepの-A(after)および-B(before)スイッチを使用して、一致する前の1行とその後の1行を含めるように指示できます。

$ grep -A 1 -B 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

検索語の前後に同じ行数が必要な場合は、-C(コンテキスト)スイッチを使用できます。

$ grep -C 1 "42B" sample.txt
Pseudo name=Apple
Code=42B
state=fault

複数の行を一致させるときにより厳密にしたい場合は、ツールを使用して、pcregrep複数の行にわたってパターンを一致させることができます。

$ pcregrep -M 'Pseudo.*\n.*42B.*\nstate.*' sample.txt
Pseudo name=Apple
Code=42B
state=fault

上記のパターンは次のように一致します。

  • -M -複数行
  • 'Pseudo.*\n.*42B.*\nstate.*'-最初の文字列が単語で始まり"Pseudo"、行末までの\n任意の文字、文字列までの"42B"任意の文字、行末までの任意の文字(\n)、文字列が続く文字列のグループに一致します"state"任意の文字が続きます。

5
-Cと同じ場合-A、(コンテキスト)をショートカットとして使用できます-B
デビッドバガーマン

@DavidBaggerman-ありがとう。答えに追加しました。
slm

なぜ1つの反対票ですか?これは質問に答えます。
slm

4

おそらくawkで同様の簡単な方法がありますが、perlでは次のようになります。

cat file | perl -ne 'BEGIN { $/="\n\n" }; print if $_ =~ /42B/;'

基本的には、ファイルを空白行で区切られたチャンクに分割し、正規表現に一致するチャンクのみを印刷するということです。


10
これは、オプションと省略表現を使用して、cat ;の無駄な使用をなくすことで簡単にできます。perl -00 -ne 'print if /42B/' file
トリプリー

4

grepいくつかのUnix系のは、持っている-p「段落」の旗を。AIXが知ってます。

grep -p 42B <myfile>

あなたがそこに求めていることを正確に行うでしょう。YMMVおよびGNU grepにはこのフラグがありません。


-pフラグがあるとすばらしいでしょう。特に-vと一緒に使用すると、出力から段落全体を除外できます。
IllvilJa

2

末尾の空行のない他のperlソリューション:

perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo

% perl -00ne 'if ($_ =~ /42B/) {chomp($_); printf "%s\n",$_}' foo
Pseudo name=Apple
Code=42B
state=fault

% cat foo
Pseudo name=Apple
Code=42B
state=fault

Pseudo name=Prance
Code=43B
state=good

1
tripleeがコメントに書いたように、より短い(したがって読みやすい) perl -00 -ne 'print if /42B/' file
mivk
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.