http://www.perlmonks.org?node_id=905819

austin43 has asked for the wisdom of the Perl Monks concerning the following question:

Hello Monks, I am trying to figure out how to automatically search and comment out specific lines within the /etc/sudoers file. I have the following lines to change...
Defaults env_reset Defaults requiretty
I need them to look like...
#Defaults env_reset #Defaults requiretty
I tried the following lines of code in backticks...
`perl -pi -e 's/.+Defaults env_reset.+/ #Defaults env_reset/g' /etc/sudoers` `perl -pi -e 's/.+Defaults requiretty.+/ #Defaults requiretty/g' /etc/sudoers`
The ".+" is to match any number of characters before or after the phrase. I think I may be using it wrong, but I am not sure. Any thoughts or ideas are greatly appreciated. Thanks in advance!

Replies are listed 'Best First'.
Re: Perl search and replace
by johngg (Canon) on May 19, 2011 at 22:27 UTC

    You could probably use a look-ahead and anchor the the beginning of the line.

    perl -pi.BAK -e 's{^(?=Defaults\s+(?:env_reset|requiretty))}{#}'

    I hope this is helpful.

    Cheers,

    JohnGG

Re: Perl search and replace
by wind (Priest) on May 19, 2011 at 22:27 UTC
    perl -pi -e 's/^(?=Defaults\s+(?:env_reset|requiretty))/#/'
Re: Perl search and replace
by 7stud (Deacon) on May 19, 2011 at 23:02 UTC

    1) Lookarounds aren't needed.

    2)

    Here is a one-liner: perl -pi -e '$_ = "#$_" if /^\s*Defaults (requiretty|env_reset)\s*$ +/'

    You match the spaces and then you keep them in the modified line--the op wants to remove the leading spaces (and possibly the trailing spaces?). That's why the people up there ^ were using lookarounds.

    use strict; use warnings; use 5.010; my $str =<<"ENDOFSTRING"; Defaults env_reset Defaults requiretty ENDOFSTRING open(my $INPUT, '<', \$str) or die "Couldn't open for string io: $!"; while (my $line = <$INPUT>) { $line =~ s{ \s* ( Defaults \s* (env_reset | requiretty) ) \s* } {#$1}xms; say "-->$line<--"; } close $INPUT; --output:-- -->#Defaults env_reset<-- -->#Defaults requiretty<--
Re: Perl search and replace
by apomatix (Novice) on May 19, 2011 at 22:44 UTC

    Probably you don't want to use ., since it will match anything, including a line beginning with something like "XDefault". Also, the + matches one or more, so the regex you wrote would only match if there was at least one character in front of the D. If you want to enforce that there is only whitespace at the beginning or end then use \s* instead of .+, and also anchor at both beginning and end. So your regex becomes /^\s*Defaults    (requiretty|env_reset)\s*$.

    Here is a one-liner:

    perl -pi -e '$_ = "#$_" if /^\s*Defaults    (requiretty|env_reset)\s*$/'

Re: Perl search and replace
by eye (Chaplain) on May 20, 2011 at 06:38 UTC
    I'm sure there are good reasons for doing this, but it should be pointed out that editing the sudoers file should only be done using the visudo command. visudo provides a locking mechanism to prevent concurrent editing and performs sanity checks on the file.

    Even if you choose to bypass visudo, it is still helpful to invoke it to test for error with the -c option.

Re: Perl search and replace
by thargas (Deacon) on May 20, 2011 at 11:50 UTC

    I would suggest, if this isn't a one-time thing, that a better approach to automatically editing important files is not to do that. I prefer instead to generate them from an authoritative, structured source. This combines nicely with generating them and the distributing them to multiple hosts.

    I've found that automatic editing often becomes automatic mutilation. If you store the data in a structured form (think database), you can do interesting reporting and searching as well.

    If you do go this route, make sure your restore process works first.