sed: 最初の x 個の出現箇所にテキストを追加する方法

sed: 最初の x 個の出現箇所にテキストを追加する方法

最初に x 回発生した行の末尾にテキストを追加しようとしています。グローバルに、また n 回目の発生に対してそれを実行する方法はわかっています。最初の n 回目の発生に対してそれを実行する方法がわかりません。例として、次の内容を含む text.txt ファイルがあります。

This is a test
junk
This is a test
More junk
This is a test
This is a test
This is a test

そして、「これはテストです」が最初に 3 回出現したときに、その最後に「.」を追加したいと思います。取得しようとしている出力は次のとおりです。

This is a test.
junk
This is a test.
More junk
This is a test.
This is a test
This is a test

答え1

This.*testは正しい正規表現です。アスタリスクは「前の文字の 0 回以上」を意味するため、This*testどの行にも一致しません。

さて、Sed は算数が苦手です。エレガントなものをお探しなら、Awk をお勧めします。

awk '/This.*test/{c++};{print $0 (c<4 ? "." : "")}' file

Awk 内の未設定の変数はゼロとして扱われると言うだけで十分だと思いますcが、さらに説明が必要な場合はお知らせください。

答え2

3 つの出現すべてがすでに見つかった後に正規表現のマッチングを行わないようにする別のバリ​​エーション:

awk -v n=3 'n && /This is a test/ {n--; $0 = $0 "."}; {print}'

具体的にはsed、次のようなことができます。

sed '
  1 {
    x
    s/^/.../
    x
  }
  /This is a test/ {
    s/$/./
    x
    s/.//
    /./ {
      x
      b
    }
    g
    :1
    $! {
      n
      b 1
    }
  }'

ここで、ホールド スペース内の.対応する数として追加する の数を追跡します。.

言うまでもなく、 はsedこの種のタスクにはあまり適していません。 が必要な理由が、いくつかの実装で見られるインプレース編集の拡張機能 ( から借用sed)である場合、 の GNU 実装は¹でもこれを行うことができることに注意してください。または、実際のものを使用することもできます。-iperlawk-i /usr/share/awk/inplace.awk

perl -lpi -e '
  if ($n < 3 && /This is a test/) {
    $n++;
    $_ .= ".";
  }' your-file

が少なくとも 1 回出現するすべての行ではなく、 が.出現するたびにを追加する場合も、最適な選択肢になります。This is a testThis is a testperl

perl -pi -e 's{This is a test\K}{$n++ < 3 ? "." : ""}ge' your-file

¹使ってはいけません-i inplaceは、まず現在の作業ディレクトリから拡張機能(または)gawkをロードしようとしますが、そこに誰かがマルウェアを仕掛けている可能性があります。で提供される拡張機能のパスはシステムによって異なる場合があります。inplaceinplaceinplace.awkinplacegawkgawk 'BEGIN{print ENVIRON["AWKPATH"]}'

答え3

示されているようperlに実行できます

perl -lpe '
  $_ = $k == 3 ? next : s/This is a test(?{$k++}).*\K/./r;
' file

象もダンスをすることができますが、ステップは単純です。GNU sed拡張正規表現モードでの書き込みを使用すると-E 、カウントをホールド内の改行の数として保存できます。

K=3
sed -Ee '
  /This is a test/!b
  G
  /(.*\n){'"$K"'}.*\n/!{
    s/\n+/./p;z;H;d
  }
  s/\n+//
  :a;n;ba
' file

関連情報