web-dev-qa-db-ja.com

BSD sed:パターンのN番目のオカレンスのみを置き換えます

BSDの使用sed;

次の置換を実行するにはどうすればよいですか?:

前:

hello hello hello
hello hello hello

後:

hello world hello
hello hello hello

言い換えると; the[〜#〜] n [〜#〜]thパターンの発生
(またはこの場合;the2ndパターンの発生?)

4
voices

任意のPOSIXsedの場合:

$ sed -e'/hello/{' -e:1 -e'$!N;s/hello/world/2;t2' -eb1 -e\} -e:2 -en\;b2 <file
hello world hello
hello hello hello
  • 最初の一致/hello/の後、ループが発生します。

  • ループ:1内で、各Next行をパターンスペースに読み取り、2ndオカレンスに対してのみsubstituteコマンドを実行します。置換が成功したかどうかをtestします。はいの場合、ループ:2に遭遇します。そうでない場合は、b1でループを繰り返します。

  • ループ:2の内側では、ファイルの終わりまで残りの行を出力するだけです。

このアプローチでは、2つの間のすべてのものがパターン空間に格納されることに注意してくださいhello。最初と2番目が互いに離れている場合、巨大なファイルで問題になります。

1
cuonglm

2つのsedsを使用すると、より簡単になります。実際、多くのことがあり、少なくともマルチコアシステムでは、そのようになっていることがよくあります高速

_:    infile =;<<"" \
sed -e's/$/ /;s/hello/&\n\n/g' -e'# marks lines with " $" and splits matches' |
sed -e:n   -e's/ $//;t'  -eG   -e'# sets up a test label, branches for " $"'  \
    -e's/o\n\{20\}$/o world/'  -e'# stacks a byte per match, edits nth match' \
    -e'x;N;x;N;s/\n\n*//;tn'   -e'# completes the stacking; recycles to top'  \
>outfile
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
_

_hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello world hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
_

(BSD sedでは、右側の置換フィールドの_\n_エスケープのnの代わりにリテラル改行が必要になります)

通常、ストリームエディタを適応させるよりもストリームを適応させる方が簡単です。上記のシーケンスはまさにそれを行います。入力の各行全体を末尾のスペースでマークしますが、それ以外の場合は、helloの出現ごとに出力行を分割します。次に、2番目のsedは、スペースで終わっていない行を探して、スタックカウントをインクリメントする必要があることを認識し、20番目に明示的に一致するだけで済みます。

もちろん、それほど厳密である必要はありません。 _\n\{20\}$_の前に先頭のoを削除し、置換から除外することができます。これは、from 20番目の一致から最後の入力までのみを置き換えます。または、_\n\{20,25\}_を実行して、一致範囲のみを処理することもできます。または、\n\{20,25\}\(\n\{15\}\)*$は、20,25の範囲を処理し、その後は10,15回ごとに処理します。

これは、最後に述べたものと同じ入力が与えられた場合の出力サンプルです...


_hello hello hello hello hello hello hello hello hello
hello hello hello hello hello hello hello hello hello
hello hello world hello world hello world hello world hello world hello world hello hello
hello hello hello hello hello hello hello hello world hello world
hello world hello world hello world hello world hello hello hello hello hello
hello hello hello hello hello world hello world hello world hello world hello world
hello world hello hello hello hello hello hello hello hello
_
0
mikeserv