Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl/Sed command to replace same pattern multiple times

I need to set disable=no in /etc/xinetd.d/chargen using commands like perl or sed.

/etc/xinetd.d/chargen content is:

# 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 
}

I have used perl command

perl -0777 -pe 's|(service chargen[^\^]+)disable\s+=\syes|\1disable=no|' /etc/xinetd.d/chargen 
but it is replacing at only one place.
# 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
}

what is the proper command to make it work in both places?

NOTE: I could have replaced disable = yes with disable = no without matching service chargen but I need to use same sed/perl command to replace in /etc/xinetd.conf which will have other services too.

UPDATE As Jonathan highlighted in his comment, disable can be at any position inside the flower bracket.

like image 428
Naive Avatar asked Jun 16 '26 12:06

Naive


1 Answers

Using sed, you can use:

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

The first part searches for ranges of lines from one starting service chargen to the first line afterwards that starts with }; within that range, it looks for lines containing disable = yes with arbitrary numbers of spaces between disable and the = yes, and changes the yes to no. If necessary, you can make the regexes fussier (no trailing white space; don't edit service chargen2018 blocks, demand the } have no trailing blanks, etc.) but it probably isn't necessary.

You can often do in-place editing, but beware of differences between systems in the semantics of how you do that. (BSD and macOS require -i ''; GNU only requires -i; both accept -i.bak and it means the same in both — but you have a backup file to cleanup.)

like image 137
Jonathan Leffler Avatar answered Jun 19 '26 01:06

Jonathan Leffler