sed 更改不同匹配的第一个匹配

sed 更改不同匹配的第一个匹配

我想更改文本文件中特定组的PATH和。LOC_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]开始的行到下一行的所有内容不变[,请在两个表达式之间选择一个带有逗号的地址范围(现​​在您只有要更改的块),用 an 反转它!(现在您得到了其他一切)并使用命令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

awk使用Perl可能更容易:

$ 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 (不仅仅是第一个),但我不确定是否可以有多个。

相关内容