sed は、他の一致の最初の一致を変更します。

sed は、他の一致の最初の一致を変更します。

テキストファイルの特定のグループの合計を変更したいと思いますPATHLOC_NAME

たとえば、

[a]
PATH=/tmp
SUR=Y
LOC_NAME=USA
[b]
PATH=/tmp
SUR=N
LOC_NAME=UK

したがって、検索するには、[b]それ以降の最初の一致のみを変更したいと思います(次の代わりに次の項目以降[*])。

sed -i '/PATH/c\PATH=\/u01'
sed -i '/LOC_NAME/c\LOC_NAME=RUS'

答え1

あなたは非常に近いです!

以下を追加できます。アドレス範囲変更すべき部分について。ブロック外の[b]すべての項目を変更せずに始まる行から次の行まで維持するには、2つの[式の間にカンマ付きのアドレス範囲を選択し(今は変更したいブロックのみがあります)、逆に!(今は変更したいブロックのみがあります)、他のすべてを取得します)コマンドを使用してbスクリプトの最後に分岐します。したがって、各後続のコマンドはその範囲の行にのみ影響します。

sed -i '/^\[b\]$/,/^\[/!b
  /PATH/c\PATH=\/u01
  /LOC_NAME/c\LOC_NAME=RUS'

もちろん、{commands;...;}逆方向と分岐の代わりにブロックを使用して逆方向ではなくマッチングを実行することもできますが、これは読みやすくなると思います。

変数の単語を識別子として使用するには、次のようにします。

ID=foo
sed -i '/^\['$ID'\]$/,/^\[/!b
  /PATH/c\PATH=\/u01
  /LOC_NAME/c\LOC_NAME=RUS'

答え2

awkPerlを使用する方が簡単かもしれません。

$ cat input
[a]
PATH=/tmp
[b]
PATH=/tmp
OTHERPATH=/somedir
[c]
PATH=/tmp

$ gr="[b]"
$ repl=/u01
$ awk -vgr="$gr" -vrepl="$repl"  '/^\[.*\]$/ { group=$0 } group == gr && /^PATH=/ { $0 = "PATH=" repl } 1' input
[a]
PATH=/tmp
[b]
PATH=/u01
OTHERPATH=/somedir
[c]
PATH=/tmp

$ gr=b
$ repl=/u01
$ gr=$gr repl=$repl perl -pe '$group = $1 if /^\[(.*)\]$/; s,^PATH=.*,PATH=$ENV{repl}, if $group eq $ENV{gr}' < input
[same output]

アイデアは、行を見つけて[something]名前を記録し、その行に対して条件付き置換を実行することです。 (awkバージョンは括弧でグループ名を使用しますが、Perlバージョンはそうではありません。後者はよりきれいですが、awkではPerlほど単純ではありません。Perlバージョンは環境を介して変数を取得するため、次のことを行う必要がありますexport grrepl同じコマンドラインから割り当てます。

キーがある場合にのみ交換するように変更しましたが、PATHまだPATH同じタイトル(最初のタイトルだけでなく)の下の[b]すべてのsを変更しますが、複数を持つことができるかどうかはわかりません。

関連情報