Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

Basically I have a situation where I frequently need to modify my hosts file to access different servers at my workplace. In an attempt to automate the process. I've been trying to use sed to make the changes I need. Basically I am trying to preserve the whole line for some IP's and comment out other IP's.

For IP's that start with 10.4. To uncomment via sed, I've attempted this

sed -i '/#10\.4\..*/c\10\.4\..*' /etc/hosts

which replaced all the matching lines with 10.4..* instead of preserving the whole line. I've also attempted this in an attempt to use a group/match:

sed -i '/#10\.4\.(.*)/c\10\.4\.\1' /etc/hosts

but this just silently fails without making any changes at all.

What am I doing wrong?

share|improve this question
add comment

2 Answers

up vote 5 down vote accepted

To remove comments from lines that have an IP starting with 10.4 (this will remove the first #, I am assuming you will never have more):

sed -i '/^#10\.4/{s/^#//}' /etc/hosts

To add a comment to those lines:

sed -i '/^10\.4/{s/^/#/}' /etc/hosts

So, why was yours failing? You were using c\ which means:

c\
text

Delete the lines matching the address or address-range, and output the lines of text which follow this command (each but the last ending with a \, which are removed from the output) in place of the last line (or in place of each line, if no addresses were specified). A new cycle is started after this command is done, since the pattern space will have been deleted.

So, when you ran sed -i '/#10\.4\..*/c\10\.4\..*' /etc/hosts, this meant "replace #10\.4\..* with the literal string #10\.4\..*". What you wanted to do is:

sed -i 's/#10\.4\.\(.*\)/10.4.\1/' /etc/hosts`

The above uses a substitution operator (s/from/to/) and pattern capturing, the first pattern in \( \) can be referred to as \1, the second as \2 etc. As you can see from Michael's answer this is not needed either, you can just replace #10.4 with 10.4. Or, as in my answer above, you can simply remove the # alone.

share|improve this answer
    
For removing the comment, I'd be conservative and add an ^ anchor in both regexes, in case the file has 210.4.5.6 foobar # this is a host –  glenn jackman Feb 10 at 20:49
    
@glennjackman good point. That's how I had it originally but then though of cases where there were leading spaces. Still, comments after the IP are very likely as you point out so answer edited, thanks. –  terdon Feb 10 at 20:52
    
Fantastic, this all makes a lot of sense. One question I have, should the first command really be sed -i '/^10\.4/{s/^#//}' /etc/hosts? I think it might need to be sed -i '/^#10\.4/{s/^#//}' /etc/hosts in order to find lines that start with a #. –  BCqrstoO Feb 11 at 17:47
    
@SonofLysander yes, you're quite right, that was a mistake. Fixed now. –  terdon Feb 11 at 17:48
    
Cooool, thanks again for all your help. This has made changing my hosts file trivial :) –  BCqrstoO Feb 11 at 18:06
add comment

If all you want is to remove # from lines that start #10.4., you can use an s command, which replaces matching regular expressions with the given replacement text and leaves the rest of the line unchanged. Either of these work:

$ sed -i 's/^#10\.4\./10.4./' /etc/hosts
$ sed -i -r 's/^#(10\.4\.)/\1/' /etc/hosts
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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