【问题标题】:Perl/Sed command to replace same pattern multiple timesPerl/Sed 命令多次替换相同的模式
【发布时间】:2019-07-18 03:07:42
【问题描述】:

我需要使用 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|\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 = no 替换 disable = yes 而不匹配 service chargen 但我需要使用相同的 sed/perl 命令替换 /etc/xinetd.conf 中的其他服务.

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

【问题讨论】:

  • 您的替换文本中有错字disbale 而不是disable
  • [^\^]+ 更改为.*? 并在第二个| 之后添加sg 标志。并将\1 替换为$1

标签: regex perl awk sed ubuntu-16.04


【解决方案1】:

您可以使用这个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 重置报告匹配的起点。任何以前消耗的字符都不再包含在最终匹配中

【讨论】:

  • 嗨 Anubhava,对不起,我忘了提到 disable 可以在花括号内的任何位置。
【解决方案2】:

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

【讨论】:

  • 嗨,James,我也想匹配 service chrgen。无论如何,谢谢你的回答。
  • 更新为service chrgen{...}
【解决方案3】:

使用sed,可以使用:

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

第一部分搜索从以service chargen 开头的第一行到之后以} 开头的第一行的行范围;在该范围内,它查找包含disable = yes 的行,在disable= yes 之间有任意数量的空格,并将yes 更改为no。如有必要,您可以使正则表达式更加繁琐(没有尾随空格;不要编辑 service chargen2018 块,要求 } 没有尾随空格等)但可能没有必要。

您通常可以进行就地编辑,但要注意系统之间在执行此操作的语义方面的差异。 (BSD 和 macOS 需要 -i '';GNU 只需要 -i;两者都接受 -i.bak 并且两者的含义相同——但您需要清理一个备份文件。)

【讨论】:

  • 如目前所写,Perl 解决方案仅在disable 行是service chargen 描述中的第一行时才有效。它可以修改为处理disable 行,而不是第一行;无需为此修改sed 脚本。这可能不是一个值得担心的问题。
  • 是的,disable 可以在花括号内的任何位置。感谢您强调它。
  • sed -E '/^service chargen/,/^}/s/(disable *= *)yes/\1no/' 可能会短一些。
猜你喜欢
  • 2013-10-11
  • 2017-06-16
  • 2021-08-14
  • 2012-12-29
  • 1970-01-01
  • 2013-11-04
  • 1970-01-01
  • 1970-01-01
  • 2017-11-22
相关资源
最近更新 更多