web-dev-qa-db-ja.com

包括的または排他的(sed、AWK、またはPerl)の2つのパターン間の行を印刷する方法は?

次のようなファイルがあり、2つの指定されたパターンPAT1PAT2の間の行を印刷したいと思います。

1
2
PAT1
3    - first block
4
PAT2
5
6
PAT1
7    - second block
PAT2
8
9
PAT1
10    - third block

awk/sedで複数回発生する可能性のある2つのマーカーパターン間の行を選択する方法 を読みましたが、パターンを含むか除外するかのいずれかの可能な組み合わせを確認したいと思います。

2つのパターン間のすべての行を印刷するにはどうすればよいですか?

38
fedorqui

PAT1とPAT2の間の行を印刷します

$ awk '/PAT1/,/PAT2/' file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block

または、変数を使用して:

awk '/PAT1/{flag=1} flag; /PAT2/{flag=0}' file

これはどのように作動しますか?

  • /PAT1/は、/PAT2/と同様に、このテキストを持つ行と一致します。
  • /PAT1/{flag=1}は、テキストPAT1が行で見つかったときにflagを設定します。
  • /PAT2/{flag=0}は、テキストPAT2が行にある場合にflagの設定を解除します。
  • flagはデフォルトのアクションを持つパターンです。これはprint $0に対してです:flagが1の場合、行が出力されます。この方法では、PAT1が発生してから次のPAT2が表示されるまでに発生するすべての行が出力されます。また、PAT1の最後の一致からファイルの最後までの行を出力します。

PAT1とPAT2の間の行を印刷します-PAT1とPAT2は含まれません

$ awk '/PAT1/{flag=1; next} /PAT2/{flag=0} flag' file
3    - first block
4
7    - second block
10    - third block

これはnextを使用してPAT1を含む行をスキップし、これが出力されないようにします。

nextへのこの呼び出しは、ブロックを再配置することでドロップできます:awk '/PAT2/{flag=0} flag; /PAT1/{flag=1}' file

PAT1とPAT2の間の行を印刷-PAT1を含む

$ awk '/PAT1/{flag=1} /PAT2/{flag=0} flag' file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block

flagを最後に配置すると、PAT1またはPAT2に設定されたアクションがトリガーされます。PAT2ではなく、PAT1に印刷されます。

PAT1とPAT2の間の行を印刷-PAT2を含む

$ awk 'flag; /PAT1/{flag=1} /PAT2/{flag=0}' file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block

flagを最初に配置することにより、以前に設定されたアクションをトリガーし、開始パターンではなく終了パターンを印刷します。

PAT1とPAT2の間の行を印刷します-他のPAT2が発生しない場合、最後のPAT1からファイルの終わりまでの行を除外します

これは、 Ed Mortonによる解決策 に基づいています。

awk 'flag{
        if (/PAT2/)
           {printf "%s", buf; flag=0; buf=""}
        else
            buf = buf $0 ORS
     }
     /PAT1/ {flag=1}' file

ワンライナーとして:

$ awk 'flag{ if (/PAT2/){printf "%s", buf; flag=0; buf=""} else buf = buf $0 ORS}; /PAT1/{flag=1}' file
3    - first block
4
7    - second block

# note the lack of third block, since no other PAT2 happens after it

これにより、選択したすべての行がバッファに保持され、PAT1が見つかった時点からデータが入力されます。その後、PAT2が見つかるまで、次の行で埋め続けられます。その時点で、保存されたコンテンツを印刷し、バッファーを空にします。

63
fedorqui

PCREでgrepを使用して(利用可能な場合)マーカーとマーカー間の行を印刷

$ grep -Pzo "(?s)(PAT1(.*?)(PAT2|\Z))" file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block
  • -P Perl-regexp、PCRE。すべてのgrepバリアントではありません
  • -z入力を一連の行として扱い、各行は改行ではなくゼロバイトで終了します
  • -o一致のみを印刷
  • (?s) DotAll、つまりドットは改行も検索します
  • (.*?)貪欲でない検索
  • \Z文字列の末尾、または末尾の改行の前でのみ一致

エンドマーカーを除くマーカー間の行を印刷

$ grep -Pzo "(?s)(PAT1(.*?)(?=(\nPAT2|\Z)))" file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block
  • (.*?)(?=(\nPAT2|\Z))\nPAT2および\Zの先読みによる非欲張りな検索

マーカーを除くマーカー間の線を印刷

$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(?=(\nPAT2|\Z)))" file
3    - first block
4
7    - second block
10    - third block
  • (?<=PAT1\n)PAT1\nの肯定的な後読み

開始マーカーを除くマーカー間の行を印刷

$ grep -Pzo "(?s)((?<=PAT1\n)(.*?)(PAT2|\Z))" file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block
5
James Brown

ここに別のアプローチがあります

両方のパターンを含める(デフォルト)

$ awk '/PAT1/,/PAT2/' file
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block

両方のパターンをマスクする

$ awk '/PAT1/,/PAT2/{if(/PAT2|PAT1/) next; print}' file
3    - first block
4
7    - second block
10    - third block

マスク開始パターン

$ awk '/PAT1/,/PAT2/{if(/PAT1/) next; print}' file
3    - first block
4
PAT2
7    - second block
PAT2
10    - third block

マスク終了パターン

$ awk '/PAT1/,/PAT2/{if(/PAT2/) next; print}' file
PAT1
3    - first block
4
PAT1
7    - second block
PAT1
10    - third block
4
karakfa

完全を期すために、ここにPerlソリューションがあります。

PAT1とPAT2の間の行を印刷-PAT1とPAT2を含む

Perl -ne '/PAT1/../PAT2/ and print' FILE

または:

Perl -ne 'print if /PAT1/../PAT2/' FILE

PAT1とPAT2の間の行を印刷-PAT1とPAT2を除外

Perl -ne '/PAT1/../PAT2/ and !/PAT1/ and !/PAT2/ and print' FILE

または:

Perl -ne 'if (/PAT1/../PAT2/) {print unless /PAT1/ or /PAT2/}' FILE 

PAT1とPAT2の間の行を印刷-PAT1のみを除外

Perl -ne '/PAT1/../PAT2/ and !/PAT1/ and print' FILE

PAT1とPAT2の間の行を印刷-PAT2のみを除外

Perl -ne '/PAT1/../PAT2/ and !/PAT2/ and print' FILE

こちらもご覧ください:

  • perldoc perlop文法の詳細については、/PAT1/../PAT2/の範囲演算子セクション:

範囲演算子

...スカラーコンテキストでは、「..」はブール値を返します。演算子は、フリップフロップのように双安定であり、sed、awk、およびさまざまなエディターの行範囲(コンマ)演算子をエミュレートします。

  • -nオプションについては、perldoc perlrunを参照してください。これにより、Perlがsed -nのように動作します。

  • Perl Cookbook、6.8 一連の行の抽出の詳細な説明。

1
Alex Harvey

代わりに:

sed '/START/,/END/!d;//d'

これにより、STARTとENDの間の行を除くすべての行が削除され、//dはsedが前のパターンを使用するため、//はSTART行とEND行を削除します。

1
Daedelus

sedを使用すると、パターンスペースの通常の印刷を抑制-nを使用して、必要な処理を実行できます。 includeにできる結果のパターン:

$ sed -n '/PAT1/,/PAT2/p' filename
PAT1
3    - first block
4
PAT2
PAT1
7    - second block
PAT2
PAT1
10    - third block

excludeパターンを指定し、それらの間にあるものだけを出力します。

$ sed -n '/PAT1/,/PAT2/{/PAT1/{n};/PAT2/{d};p}' filename
3    - first block
4
7    - second block
10    - third block

として分解します

  • sed -n '/PAT1/,/PAT2/-PAT1PAT2の間の範囲を見つけ、印刷を抑制します。

  • /PAT1/{n};-PAT1と一致する場合は、n(次の)行に移動します。

  • /PAT2/{d};-PAT2に一致する場合は、行を削除します。

  • p-/PAT1/,/PAT2/に該当し、スキップまたは削除されなかったすべての行を出力します。

1
David C. Rankin