sed スクリプトは、最後のパターン発生と空行の間に行を印刷します。

sed スクリプトは、最後のパターン発生と空行の間に行を印刷します。

sedを使用して、最後のパターンの発生と空白行の間のテキストを印刷したいと思います。たとえば、次のファイルから:

$ cat file
pattern
1
2
3


pattern
4
5


pattern
6
7
8
9


10
11


ただ印刷したい

6
7
8
9

sed '/pattern/{:1;$!{/^$/!{N;b1};h}};${x;p};d' fileから試してみるここしかし、うまくいきません。

編集:これはほとんど動作します:

$ sed -n -e '/pattern/ {n; :a; $!{/\n$/!{N;ba};h} }; $ { x;p }' file
6
7
8
9

最後に空白行を削除する方法は?

Edit2:これはうまくいく解決策です。

$sed '/pattern/{:1;$!{/\n$/!{N;b1};h}};${x;s/pattern\n//;s/\n$//;p};d' file
6
7
8
9

Edit3: これは良いです:

$sed '/pattern/{:1;$!{/\n$/!{N;b1};s///;h}};${x;s/pattern\n//;p};d' file

答え1

ストリームエディタを使用してsedパターンレコードを検出し、そこから行をスキップし、次の空行が見つかるまで繰り返します。それまではパターン空間のレコードが蓄積され、ループ後はホールド空間の内容をパターン空間の内容で上書きします。これはすべてのパターン...空のラインブロックに対して再び発生します。ファイルの末尾で保留内容を検索し、空でない場合は印刷します。

$ sed -ne '
  /pattern/{
    $d;n
    :loop
      s/\n$//;tdone
      $bdone;N
    bloop
    :done
    x
  }
  ${x;/./p;}
' file
6
7
8
9

最大。ラインエディタはこの範囲のような問題に自然に適しています。編集する

ed -s file <<\eof
a

.
?pattern?+1;/^$/-1p
Q
eof

GNU sedエディタを使用する別の方法は、範囲演算子を使用して予約済みスペースのブロックを収集することです。

sed -e '
  /pattern/,/^$/!ba
  /./!ba
  H;/pattern/{z;x;}
  :a
  $!d;x;s/.//
' file

私たちはSlurpモードでGNU sedエディタを使用することができ、パターンの最後のインスタンスに到達するために正規表現の欲張りな特性を使用できます。

sed -Ez '
  s/.*pattern\n(([^\n]+\n)+)(\n.*)?/\1/
' file

以下はPerlの範囲演算子に対応するsedです。 Array@Aはブロックラインの集水ゾーンとして機能します。

perl -ne 'next unless
  my $e = /pattern/ .. /^$/;
  @A = $e == 1 ? ()
     :   /./   ? (@A, $_)
     :            @A;
  }{print @A;
' file

答え2

awk '/pattern/,/^$/ { arr[NR]=$0; if (/pattern/) line1=NR; if (/^$/) line2=NR}END{ if (line1) for(i=++line1;i<line2;i++) print arr[i]}' file

/pattern/,/^$/パターンと空白行の間に線が生じます。

次に、if (/pattern/) line1=NRパターンが見つかった最後の行のレコード番号を提供します。if (/^$/) line2=NR最後の空行の行番号を提供しますパターンを見つけた後

最後に、2つのレコード間のforループは予想される出力を返します。

パターンと次の空行の間に2行がない、パターンがファイルにない、またはパターンの外に空行がない場合、この操作は失敗します。 (からインポートここ)

答え3

私の考えでは、以前のソリューションこの問題を解決するために拡張することもできます。

printf '%s\n' '?pattern?+1' '. +1,/^$/ -1 p' | ed -s file

これにより、次のアドレスに2つのコマンドが送信されますed

  • ?pattern?+1- ファイルの末尾から戻るパターンを検索し、一致するものを1行進めると、その行が印刷されます。
  • . +1,/^$/ -1 p- 次の行(現在の行+ 1)から次の空の行()の前の行まで/^$/ -1印刷します。

patternそのジョブと次の空行の間に2行がない、patternファイルにない、または後に空行がない場合、patternこの操作は失敗します。

答え4

これはおそらく最も簡単ですawk

$ awk -v RS='' -F '\n' '$1 ~ /pattern/ { hold = $0 } END { if (hold != "") print hold }' file | sed 1d
6
7
8
9

awkRSこれは、「短絡読み取りモード」に入る空の入力レコード区切り文字で使用されます。awkつまり、一度に全体の段落を取得します$0。これは、段落の最初の行と同様に、-F '\n'段落の各行が別々のフィールドになるという意味でも使用されます。$1

このコードは、正規表現が段落patternの最初の行と一致するかどうかをテストします。その場合、変数は段落を保持しますhold

最後に空でholdない場合は印刷してください。

sed出力の最初の行(一致する行pattern)を削除するために使用されます。

$pattern静的モードの代わりにシェル変数を使用するには、次のようにします。

pattern=$pattern awk -v RS='' -F '\n' '$1 ~ ENVIRON["pattern"] { hold = $0 } END { if (hold != "") print hold }' file | sed 1d

関連情報