Perl / Sed命令多次替换相同的模式

时间:2019-02-24 16:17:25

标签: regex perl awk sed ubuntu-16.04

我需要使用诸如perl或sed之类的命令在disable=no中设置/etc/xinetd.d/chargen

/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|\1disable=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 = yes替换disable = no而没有匹配service chargen,但是我需要使用相同的sed / perl命令替换{{1 }}也将提供其他服务。

更新正如乔纳森(Jonathan)在其评论中强调指出的那样,禁用可以在花括号内的任何位置。

3 个答案:

答案 0 :(得分:3)

使用sed,您可以使用:

sed -e '/^service chargen/,/^}/ { /disable *= yes/ s/yes/no/; }'

第一部分搜索从service chargen到一个以}开始的第一行之间的行范围;在此范围内,它将查找包含disable = yes且在disable= yes之间具有任意空格的行,并将yes更改为no。如有必要,可以使正则表达式更容易处理(没有尾随空格;不要编辑service chargen2018块,要求}没有尾随空格等),但这可能不是必需的。 / p>

您通常可以进行就地编辑,但是要注意系统之间在执行语义上的差异。 (BSD和macOS要求-i ''; GNU仅要求-i;它们都接受-i.bak,两者含义相同-但您有一个要清除的备份文件。)

答案 1 :(得分:2)

您可以使用以下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
}

RegEx Demo

\K重置报告的比赛的起点。所有以前消耗的字符将不再包含在最终比赛中

答案 2 :(得分:1)

好吗?:

$ 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 *=/)。