trying to get 'sed' to work

Hi I'm trying to use sed in a sudoers file.

This works from root and removes this number sign.
sed -i '' 's/# %wheel ALL=(ALL) NOPASSWD: ALL/%wheel ALL=(ALL) NOPASSWD: ALL/' /usr/local/etc/sudoers

However this one doesn't
sed -i "" 's/# %sudo ALL=(ALL) ALL/%sudo ALL=(ALL) ALL/' /usr/local/etc/sudoers

can someone else test this.
 
Code:
/usr/local/etc/sudoers: No such file or directory

Seriously though, it should have worked if there's such line to match in sudoers:
Code:
$ echo '# %sudo ALL=(ALL) ALL' | sed 's/# %sudo ALL=(ALL) ALL/%sudo ALL=(ALL) ALL/'
%sudo ALL=(ALL) ALL
 
Paul Belair , the problem is that you rely on particular characters, and even an extra space (which may appear in the future) will brake your script. In this particular case there is a tab character.
I'd suggest making the pattern more universal (not perfect though, you can work on it further):
Code:
sed -i '' 's/#\(.*%sudo.*ALL=(ALL).*ALL.*\)/\1/' /usr/local/etc/sudoers
You can test it first by running:
Code:
sed -n 's/#\(.*%sudo.*ALL=(ALL).*ALL.*\)/\1/p' /usr/local/etc/sudoers
[EDIT] Fixed typos
 
Thanks both
The replacement text left a space at the beginning of the line. This worked
sed -i '' 's/#\(.*%sudo.*ALL=(ALL).*ALL.*\)/%sudo ALL=(ALL) ALL/' /usr/local/etc/sudoers
 
As I mentioned above, the pattern can still be improved, for example, you can tell sed that the "spaces" are any number of spaces or tabs by using [:blank:]:
Code:
sed -i '' 's/#[[:blank:]]*\(%sudo[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL.*\)/\1/p' /usr/local/etc/sudoers
Pay attention that the first "space" is outside of the remaining pattern now, thus you'll not get it in the result.
 
Thanks. I found that the "/p" at the end was causing the line to both be uncommented, and duplicated. I instead replaced it with "/g".

The command which works for me:
Code:
sed -i '' 's/#[[:blank:]]*\(%wheel[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL.*\)/\1/g' /usr/local/etc/sudoers

Output showing the issue with "/p" and the improved output of "/g":
Code:
# cp /usr/local/etc/sudoers.dist /usr/local/etc/sudoers
# sed -i '' 's/#[[:blank:]]*\(%wheel[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL.*\)/\1/p' /usr/local/etc/sudoers
# diff -u /usr/local/etc/sudoers.dist /usr/local/etc/sudoers
--- /usr/local/etc/sudoers.dist 2019-11-14 05:06:31.000000000 +0000
+++ /usr/local/etc/sudoers      2019-11-23 03:26:52.761581000 +0000
@@ -87,7 +87,8 @@
 root ALL=(ALL) ALL
 
 ## Uncomment to allow members of group wheel to execute any command
-# %wheel ALL=(ALL) ALL
+%wheel ALL=(ALL) ALL
+%wheel ALL=(ALL) ALL
 
 ## Same thing without a password
 # %wheel ALL=(ALL) NOPASSWD: ALL

# cp /usr/local/etc/sudoers.dist /usr/local/etc/sudoers
# sed -i '' 's/#[[:blank:]]*\(%wheel[[:blank:]]*ALL=(ALL)[[:blank:]]*ALL.*\)/\1/g' /usr/local/etc/sudoers
# diff -u /usr/local/etc/sudoers.dist /usr/local/etc/sudoers
--- /usr/local/etc/sudoers.dist 2019-11-14 05:06:31.000000000 +0000
+++ /usr/local/etc/sudoers      2019-11-23 03:27:37.038799000 +0000
@@ -87,7 +87,7 @@
 root ALL=(ALL) ALL
 
 ## Uncomment to allow members of group wheel to execute any command
-# %wheel ALL=(ALL) ALL
+%wheel ALL=(ALL) ALL
 
 ## Same thing without a password
 # %wheel ALL=(ALL) NOPASSWD: ALL
 
This post really helped with modifying the sudoers file. However, I have one more line that I need to uncomment.

Code:
## Uncomment to show on password prompt which users' password is being expected
# Defaults passprompt="%p's password:"

For the life of me, I cannot get it uncommented...

Any ideas?
 
You should be using /usr/local/bin/visudo to edit /usr/local/etc/sudoers to prevent locking yourself out after a syntax error.

However, try removing the comment at the BOL:
Bash:
/usr/bin/sed -i'' -E 's|^#[[:space:]]+\%sudo|\%sudo|' /usr/local/etc/sudoers
 
With a little bit of difference there is also,
 
You should be using /usr/local/bin/visudo to edit /usr/local/etc/sudoers to prevent locking yourself out after a syntax error.
You can run visudo -c to check the validity of the sudoers files if you script those changes. Then add a way to back out the changes if the check fails. Always a good idea to do.
 
sed -E -e 's/^(# +)(Defaults passpr.*)/\2/' /usr/local/etc/sudoers
Regex is still mysterious to me, except some basics it's foggy in my brain.
^(# +) every lines that start with # followed by a white space at least ---> okay for me
(Defaults passpr.*) the line must contain the string "Default blabla" plus anything behind it ---> okay for me
/\2/' but this I do not understand ?
Could you explain it to me please, thank you.
 
So the matched string is the first parenthesis AND the second one ? or just the first parenthesis only ? that's where I am a bit lost with this syntax.
 
Regex is still mysterious to me, except some basics it's foggy in my brain.
^(# +) every lines that start with # followed by a white space at least ---> okay for me
(Defaults passpr.*) the line must contain the string "Default blabla" plus anything behind it ---> okay for me
/\2/' but this I do not understand ?
Could you explain it to me please, thank you.
The parentheses around # + and Defaults passpr.* create capturing groups, and the \2 is a back reference to the second group. Groups are numbered from left to right by opening parenthesis. E.g., given a pattern (foo(bar))(baz) any matches will have "foobar" in the first capturing group, "bar" in the second, and "baz" in the third. Java regexes store the entire match at capturing group 0. Not sure about sed(1).
 
I think I get the back reference thing, but not entirely the capturing groups.
That's probably because I need to practice Regex more.
Anyway thank you both covacat and Jose for your explanations.
 
Perhaps Sed - An Introduction and Tutorial by Bruce Barnett will be helpful (also: awk); especially because these are UNIX centered. Anyways, happy regexing :)

Regular expressions may seem easy at first but they have some intricate details and getting them right and executing them fast when necessary requires knowledge. The "ultimate" reference in regular expressions cross language and cross applications used to be Mastering Regular Expressions, 3rd Edition - 2006, don't know how well that works for modern versions of say, perl or java.
 
So the matched string is the first parenthesis AND the second one ? or just the first parenthesis only ? that's where I am a bit lost with this syntax.
I think I get the back reference thing, but not entirely the capturing groups.
So after few tries and viewing few tutorial videos I finally get all the regex parts.
Honestly I am not sure to reusing it, the concept and the logic being the back reference associated to capturing group is a bit tricky but who knows may be I'll remember it.
Thanks for the tip guys.
 
Honestly I am not sure to reusing it, the concept and the logic being the back reference associated to capturing group is a bit tricky but who knows may be I'll remember it.
Regex are very powerful and often useful. But when I look back at my own a few months afterwards I often wonder which %&#@ put hieroglyphics in there.
It helps to put a comment line above the sed containing an example of the input the sed is supposed to work on.
 
Regexes are one of the few things for which I always, always write a unit test. I can decipher them now, but this is only after decades of working with them in Perl and Java.
 
Back
Top