sed / awk 匹配文件中第二次出现的正则表达式,并替换整行
sed / awk match second occurrence of regex in a file, and replace whole line
尝试让 sed 或 awk 执行以下操作:
- 浏览文件
- 捕获字符串 + 正则表达式 (
remote_addrs.*
)
- 将整行替换为不同的内容,因此“包含“remote_addrs”及其后任何内容的行”将其替换。
示例文件:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck
想改成这样:
示例文件:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck
尝试使用以下方法:
sed -z 's/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file
sed ':a;N;$!ba;s/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file
但 sed 拒绝在发生该事件后替换所有内容。这似乎只适用于单个字符串。
这个必须完成不给出具体的行号,“remote_addrs”的行位置必须是可变的。
您使用的是 GNU sed
,所以我也发布一个 GNU sed
解决方案:
sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' file
注:
</code>(在您现在编辑的问题的初始版本中使用)是对第 3 组的反向引用,并且您的正则表达式中没有单个组。因此,应删除转义符</li>
<li>你不需要转义 spaces</li>
<li><code>\z
使换行符成为模式 space 的一部分,因此 .
匹配它们。您需要打开“多行”模式,并添加 m
标志,以便 .
模式无法匹配换行字符。
参见online demo:
#!/bin/bash
s='dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck'
sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' <<< "$s"
输出:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck
虽然 Wiktor 的 nice 解决方案已被接受,但 awk
解决方案如何 (JFYI):
awk '/remote_addrs.*/ && c++==1 {sub(/remote_addrs.*/, "remote_addrs = 3.3.3.3")} 1' file
- 正则表达式的第一个匹配只是递增变量
c
而没有调用 {...}
. 中的语句
- 第二个匹配执行
sub()
语句。
- 最后的
1
告诉awk
打印当前记录。
使用 awk 你可以试试这个
$ cat file
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck
$ awk 'set==1 && /remote_addrs/{ [=10=]="remote_addrs = 3.3.3.3" }
/remote_addrs/{ set=1 } 1' file
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck
尝试让 sed 或 awk 执行以下操作:
- 浏览文件
- 捕获字符串 + 正则表达式 (
remote_addrs.*
) - 将整行替换为不同的内容,因此“包含“remote_addrs”及其后任何内容的行”将其替换。
示例文件:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck
想改成这样: 示例文件:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck
尝试使用以下方法:
sed -z 's/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file
sed ':a;N;$!ba;s/remote_addrs.*/remote_addrs\ =\ 3.3.3.3/2' file
但 sed 拒绝在发生该事件后替换所有内容。这似乎只适用于单个字符串。
这个必须完成不给出具体的行号,“remote_addrs”的行位置必须是可变的。
您使用的是 GNU sed
,所以我也发布一个 GNU sed
解决方案:
sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' file
注:
</code>(在您现在编辑的问题的初始版本中使用)是对第 3 组的反向引用,并且您的正则表达式中没有单个组。因此,应删除转义符</li> <li>你不需要转义 spaces</li> <li><code>\z
使换行符成为模式 space 的一部分,因此.
匹配它们。您需要打开“多行”模式,并添加m
标志,以便.
模式无法匹配换行字符。
参见online demo:
#!/bin/bash
s='dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck'
sed -z 's/remote_addrs.*/remote_addrs = 3.3.3.3/2m' <<< "$s"
输出:
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck
虽然 Wiktor 的 nice 解决方案已被接受,但 awk
解决方案如何 (JFYI):
awk '/remote_addrs.*/ && c++==1 {sub(/remote_addrs.*/, "remote_addrs = 3.3.3.3")} 1' file
- 正则表达式的第一个匹配只是递增变量
c
而没有调用{...}
. 中的语句
- 第二个匹配执行
sub()
语句。 - 最后的
1
告诉awk
打印当前记录。
使用 awk 你可以试试这个
$ cat file
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 2.2.2.2
woodchuck
$ awk 'set==1 && /remote_addrs/{ [=10=]="remote_addrs = 3.3.3.3" }
/remote_addrs/{ set=1 } 1' file
dog
cat
remote_addrs = 1.1.1.1
moose
remote_addrs = 3.3.3.3
woodchuck