I'm in a bit of a conundrum. Put as simply as possible, I am trying to craft part of a script that will edit the /etc/sudoers file in linux utilizing sed. Due to the account I am using, I need to do this editing WITH sudo running the sed command. Due to this however, I can't end the command before I do all of the edits to the file otherwise I will lock myself out.

I'm specifically trying to modify the %wheel group within the /etc/sudoers file, and there are preexisting entries within the file on various servers. I want to add my own optimized entry, comment out the older entries, and finally make sure the entry I JUST added is not commented out.

I have crafted statements in sed to do this, and they run individually just fine, it's when I try to do anything to allow multiple statements in the same command that neither statement functions. (Even if I don't get any syntax errors)

For example my statements:

sudo sed 's/.*wheel/#&/' /etc/sudoers

---- works great by itself

sudo sed 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers   

---- also works great by itself

However, since I must combine them into a single command, then things stop working..... such as:

sudo sed 's/(.*wheel/#&) (^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\))/' /etc/sudoers   -

--- Nope, no dice


sudo sed -e 's/.*wheel/#&/' -e 's/^#\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers   

---- Doesn't work either

Etc, etc, nothing along those lines seems to solve the issue. The output after I run the 2 above commands shows that it is unchanged as if I just ran a cat on the original file. (yes I know I'm not permanently editing the file in place at the second)

Now I understand that yes... I could add a temporary entry at the bottom of the file for my user to begin with, and then delete it as the last step to circumvent this. Or I could run a script with a loop and likely also be successful, but there has to be a more elegant way to do it with a single command as I intended.

Anyone have any ideas? Also, if there is a better way to do what I intend to do in the first place, I'd be interested to know.

EDIT: Input/Output examples:

The lines that are in the file by default:

%wheel  ALL=(ALL)       ALL
%wheel  ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL   ---added by me in a previous step
#%wheel  ALL=(ALL)       NOPASSWD: ALL

I want the final product after sed is run to look like this:

#%wheel  ALL=(ALL)       ALL
#%wheel  ALL=(ALL)       NOPASSWD: ALL

I don't want it to look like this:

#%wheel  ALL=(ALL)       ALL
#%wheel  ALL=(ALL)       NOPASSWD: ALL

AND I don't want it to look like this:

%wheel  ALL=(ALL)       ALL
%wheel  ALL=(ALL)       NOPASSWD: ALL

Right as it is now, the multiple statement sed command doesn't seem to do anything, it's only when I execute them as separate commands that I get the desired output. (which I can't do in this circumstance)

Any help would be appreciated!

  • 1
    The sudoers file should be edited with visudo.
    – Kusalananda
    Aug 15, 2016 at 18:24
  • @ Kusalananda: The sudoers file "should" manually be edited with visudo, but I need to make automatic changes, without doing file replacement in this case. As long as it's tested and automated, I don't need visudo to verify syntax issues as I will have already rigorously tested them. @ilkkachu I do need a script to do this, I'm not going to change this by hand on over 1000 servers, that's for sure. :)
    – Viscosity
    Aug 15, 2016 at 18:51
  • Just for sake of completeness, there is an entry I put into the file before this stage of the process that I need to make sure stays uncommented. It is: %wheel ALL=(ALL) NOPASSWD: LOG_INPUT: LOG_OUTPUT: ALL Maybe that will help this make a tad more sense.
    – Viscosity
    Aug 15, 2016 at 19:04
  • It will much better if you show exampe what you have and what you'd like to receve in such long way
    – Costas
    Aug 15, 2016 at 19:18
  • @ Don_Crissti and Costas: I have done so in an edit up in the OP.
    – Viscosity
    Aug 15, 2016 at 19:30

2 Answers 2


Final edit after example added to original question:

Your second sed command with two '-e' expressions works correctly for me on the sample input provided, using Debian Jessie / sed (GNU sed) 4.2.2. (Well mostly. The last line ends up with 2 comment characters, but that shouldn't be a major issue.) Not sure if there is some variation in the way different versions of sed handle multiple expressions?

Not my preferred solution, but if you are having trouble getting sed to behave predictably with multiple expressions, you could also use tee at the end of a pipeline of individual sed commands.

sudo cat /etc/sudoers | { multiple sed commands in pipeline } | sudo tee /etc/sudoers

First edit after some clarification in the comments:

If the line that you are adding is commented out before the sed run, then the first regex is adding a second comment character to it. With two '#' characters at the beginning of the line, the second statement no longer matches and does nothing. An easy edit is to use the 1-or-more modifier on the '#' character in the second expression:

sudo sed -e 's/.*wheel/#&/' -e 's/^#\+\s*\(%wheel\s\+ALL=(ALL)\s\+NOPASSWD:\s\+LOG_INPUT:\s\+LOG_OUTPUT:\s\+ALL\)/\1/' /etc/sudoers   

Original Answer:

If I'm not mistaking your regexes, your second command is undoing the first. As a simplified example:

echo a | sed -e 's/a/b/' -e 's/b/a/'

will print a. Multiple expressions are executed in sequence for each line.

One option would be to use an alternate comment delimiter in the first step and then add a third step to sub it out. For example, instead of adding a '#' to the beginning of the line in the first expression, use 's/.*wheel/--&/'. Then after the second expression has uncommented the lines that you want, add a third -e 's/^--/#/' to clean it up.

  • OK, now that I've re-read your example more closely, it sounds undoing the first edit is in the second edit actually is what you are trying to accomplish, but you only want to undo the comment on a specific line that you previously added in a separate step?
    – Drew
    Aug 15, 2016 at 18:38
  • Correct, I am making an edit to all entries matching a pattern, and the second edit is meant to undo it on a single entry. The issue is, I don't know how many entries are in that file for the wheel group, or what values they have, or if they are even valid. So I'm going to comment them all out globally, and leave only my vetted one as active. But I don't want the global commenting to affect my vetted entry. Hopefully that makes sense.
    – Viscosity
    Aug 15, 2016 at 18:54
  • Is the vetted one you've added commented before running the sed command?
    – Drew
    Aug 15, 2016 at 18:55
  • Yes it is, in this case it would be added within a different script earlier in the "process". Honestly, I don't care when it's added, as long as I can accomplish what I need without locking out my sudo access. (No, I can't run this as root, even though that would solve my issues.) :)
    – Viscosity
    Aug 15, 2016 at 18:57
  • Drew, yeah I'm using bash version: 4.1.2(1)-release-(x86_64-redhat-linux-gnu) However, I will try both yours and Costas's solutions and see what happens!
    – Viscosity
    Aug 15, 2016 at 20:30

How I undestand OP there is need to mark all lines with wheel as comment except with text %wheel\s\+ALL …

sudo sed '
    ' /etc/sudoers
  • Thanks Costas, I'll try your solution and see what happens.
    – Viscosity
    Aug 15, 2016 at 20:30
  • @Viscosity You're Welcome. I'd offer to add to this script your previous step of addind %wheel\s\+ALL … line too
    – Costas
    Aug 15, 2016 at 20:38
  • I did make Drew's answer the "official" one, but your solution absolutely does work Costas, thanks! (I'd rank it up, but my rep is too low)
    – Viscosity
    Aug 15, 2016 at 21:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.