では簡単になりそうですが、そうできるかどうか疑問にawk
思います。sed
これは私の入力です。
line 1
line 2
line 3
line 1
line 2
line 3
line 1
line 2
line 3
line 1
2番目の正規表現を見つけ、それ以降に見つかったすべてを変更するために内部正規表現を作成したいと思いますline 3
。出力は次のとおりです。
line 1
line 2
line 3
line 1
line 2
replaced
line 1
line 2
replaced
私は実際にこの入力でのみ動作する「賢い」ソリューションを探しているわけではありません。一般的な検索と置換方法があるかどうかを知りたいです。後ろにと一致しますsed
。
解決策はどこかにあると思いました。addr
出荷書類ビーチ、ところでできることだと説明されていないようで/starting point/,s/...
、しようとするとエラーが出ます。
答え1
そのためには、目標線を見た回数を数える必要があります。残念ながら、何でも計算するのはsed
PITAです。awk
またはでこれを行うことをお勧めしますperl
。たとえば、
$ perl -p -e '$found++ if m/line 1/;
next if $found < 2;
s/line 3/replaced/' input.txt
line 1
line 2
line 3
line 1
line 2
replaced
line 1
line 2
replaced
またはawk
:
$ awk '/line 1/ { found++ };
found < 2 { print ; next };
{ sub(/line 3/,"replaced") ; print }' input.txt
line 1
line 2
line 3
line 1
line 2
replaced
line 1
line 2
replaced
これらの方法は効果的ですが、最高のソリューション、特にawk
バージョン(Perlを直接翻訳したもの)とは遠いです。
ところで、どちらのバージョンも正規表現を使って検索し、計算、検索する正規表現、変える、代替文字列、さらに必要な数までスクリプトにハードコードする代わりに、コマンドラインオプションとして使用できます。
答え2
GNUを使用するsed
(0アドレス1の場合):
$ sed '0,/^line 1$/b; /^line 1$/,$ s/^line 3$/replaced/' < file
line 1
line 2
line 3
line 1
line 2
replaced
line 1
line 2
replaced
私たちのb
牧場出る最初の0,/^line 1/
範囲の場合、これは2番目の範囲に/^line 1$/,$
2番目の発生項目に達したときにのみ開始行が表示されることを意味しますline 1
。
n番目の発生は、以下を使用してawk
簡単に見つけることができます。line 1
awk '$0 == "line 1" && ++n == 2, eof {if ($0 == "line 3") $0 = "replaced"}; 1'
(ここではeof
初期化されていない他の変数があるので、間違った代表する最初、最後範囲には終わりはありません。0
リテラルと同じ意味ですが、読みやすくなります!skip
。1
本物現在のレコードを印刷しようとしていますが、使い方が1
寛容であるため、すべてのユーザーが認識する必要があり、awk
より明確な選択肢は)です{print}
。
1でGNUを想定しているので、標準ではなく1の後に追加することsed
もできます。私たちは別の人が必要です。;more commands
b
-e 'more commands'
sed
答え3
バッファ(パターン空間)にカウンタを作成し、各行で確認します。
sed '
/^line 1/{x;/11/!s/^/1/;x}
x;/11/{x;b1};x;b
:1;s/^line 3$/replaced/
' file
1
カウンターユニットとして使用する
[更新]より良いパフォーマンス:
sed '
/^line 1$/{x;/11/!s/^/1/;x}
/^line 3$/!b
x;/11/!{x;b}
x;s/.*/replaced/
' file
パターンに一致する行でのみカウンタを確認してください -/^line 3$/
答え4
GNU sedを使用すると、保存.
スペースにポイントをポイントとして保存して操作を実行できます。
sed -e '
/^line 1$/,/^line 1$/{//!b
x;s/^$/./;x;t
:a;n;s/^line 3$/REPLACED/;ba
}
' file
もう1つの可能性は、範囲演算子を使用せずにGNU sedで拡張正規表現モードを使用することです。ここで改行文字は\n
カウンターとして機能し、予約済みスペースに保存されます。
sed -Ee '
/^line 1$/H
x;s/^(\n{1,2}).*/\1/;x
/^line 3$/G
/\n.{2}/c REPLACED
s/\n//g
' file
Perlは同様の方法で同じことを行うことができます。
perl -lpe '
s/^line 3$/$a?"REPLACED":$&/e
unless
m?^line 1$? ... /^line 1$(?{$a++})/;
' file
awk を使用すると、正規表現を変数とうまく組み合わせて 1 ずつ増やすことができます。
awk '
1 < ( k += /^line 1$/ ) &&
sub(/^line 3$/,"REPLACED") ||
1' file