最初に 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 実装は¹でもこれを行うことができることに注意してください。または、実際のものを使用することもできます。-i
perl
awk
-i /usr/share/awk/inplace.awk
perl -lpi -e '
if ($n < 3 && /This is a test/) {
$n++;
$_ .= ".";
}' your-file
が少なくとも 1 回出現するすべての行ではなく、 が.
出現するたびにを追加する場合も、最適な選択肢になります。This is a test
This is a test
perl
perl -pi -e 's{This is a test\K}{$n++ < 3 ? "." : ""}ge' your-file
¹使ってはいけません-i inplace
は、まず現在の作業ディレクトリから拡張機能(または)gawk
をロードしようとしますが、そこに誰かがマルウェアを仕掛けている可能性があります。で提供される拡張機能のパスはシステムによって異なる場合があります。inplace
inplace
inplace.awk
inplace
gawk
gawk '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