Perl/Sed 多次替换相同模式的命令
Perl/Sed command to replace same pattern multiple times
我需要使用 perl 或 sed 等命令在 /etc/xinetd.d/chargen
中设置 disable=no
。
/etc/xinetd.d/chargen
内容为:
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
我用过perl命令
perl -0777 -pe 's|(service chargen[^\^]+)disable\s+=\syes|disable=no|' /etc/xinetd.d/chargen
但它只替换了一个地方。
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable=no
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
让它在两个地方都工作的正确命令是什么?
注意:我可以用 disable = no
替换 disable = yes
而无需匹配 service chargen
但我需要使用相同的 sed/perl在 /etc/xinetd.conf
中替换的命令也将有其他服务。
更新 正如乔纳森在他的评论中强调的那样,禁用可以在花括号内的任何位置。
您可以使用这个 perl
命令:
perl -0777 -pe 's/(?m)^service chargen\s*\{[^}]*disable\s*=\s*\Kyes/no/g' file
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = no
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable = no
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
\K
重置报告匹配的起点。任何先前消耗的字符不再包含在最终匹配中
Awk 好吗?:
$ awk '/service chargen/,/}/{if(/disable/)sub(/yes/,"no")}1' file
...
disable = no
...
disable = no
...
解释:
$ awk ' # well, awk
/service chargen/,/}/ { # between service chargen {...}
if(/disable/) # if disable found
sub(/yes/,"no") # replace yes with no
}1' file # output
随意根据自己的喜好调整正则表达式 (/disable/
)(例如 /^ *disable *=/
)。
使用sed
,您可以使用:
sed -e '/^service chargen/,/^}/ { /disable *= yes/ s/yes/no/; }'
第一部分搜索从 service chargen
开头的行到之后以 }
开头的第一行的行范围;在该范围内,它查找包含 disable = yes
且 disable
和 = yes
之间任意数量的 space 的行,并将 yes
更改为 no
.如有必要,您可以使正则表达式更复杂(没有尾随白色 space;不要编辑 service chargen2018
块,要求 }
没有尾随空白,等等)但它可能不是没必要。
您通常可以进行就地编辑,但要注意系统之间在执行此操作的语义方面的差异。 (BSD 和 macOS 需要 -i ''
;GNU 只需要 -i
;两者都接受 -i.bak
,两者的意思相同——但你有一个备份文件要清理。)
我需要使用 perl 或 sed 等命令在 /etc/xinetd.d/chargen
中设置 disable=no
。
/etc/xinetd.d/chargen
内容为:
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
我用过perl命令
perl -0777 -pe 's|(service chargen[^\^]+)disable\s+=\syes|disable=no|' /etc/xinetd.d/chargen
但它只替换了一个地方。
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = yes
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable=no
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
让它在两个地方都工作的正确命令是什么?
注意:我可以用 disable = no
替换 disable = yes
而无需匹配 service chargen
但我需要使用相同的 sed/perl在 /etc/xinetd.conf
中替换的命令也将有其他服务。
更新 正如乔纳森在他的评论中强调的那样,禁用可以在花括号内的任何位置。
您可以使用这个 perl
命令:
perl -0777 -pe 's/(?m)^service chargen\s*\{[^}]*disable\s*=\s*\Kyes/no/g' file
# description: An xinetd internal service which generate characters. The
# xinetd internal service which continuously generates characters until the
# connection is dropped. The characters look something like this:
# !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefg
# This is the tcp version.
service chargen
{
disable = no
type = INTERNAL
id = chargen-stream
socket_type = stream
protocol = tcp
user = root
wait = no
}
# This is the udp version.
service chargen
{
disable = no
type = INTERNAL
id = chargen-dgram
socket_type = dgram
protocol = udp
user = root
wait = yes
}
\K
重置报告匹配的起点。任何先前消耗的字符不再包含在最终匹配中
Awk 好吗?:
$ awk '/service chargen/,/}/{if(/disable/)sub(/yes/,"no")}1' file
...
disable = no
...
disable = no
...
解释:
$ awk ' # well, awk
/service chargen/,/}/ { # between service chargen {...}
if(/disable/) # if disable found
sub(/yes/,"no") # replace yes with no
}1' file # output
随意根据自己的喜好调整正则表达式 (/disable/
)(例如 /^ *disable *=/
)。
使用sed
,您可以使用:
sed -e '/^service chargen/,/^}/ { /disable *= yes/ s/yes/no/; }'
第一部分搜索从 service chargen
开头的行到之后以 }
开头的第一行的行范围;在该范围内,它查找包含 disable = yes
且 disable
和 = yes
之间任意数量的 space 的行,并将 yes
更改为 no
.如有必要,您可以使正则表达式更复杂(没有尾随白色 space;不要编辑 service chargen2018
块,要求 }
没有尾随空白,等等)但它可能不是没必要。
您通常可以进行就地编辑,但要注意系统之间在执行此操作的语义方面的差异。 (BSD 和 macOS 需要 -i ''
;GNU 只需要 -i
;两者都接受 -i.bak
,两者的意思相同——但你有一个备份文件要清理。)