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?


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:


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.

  • For removing the comment, I'd be conservative and add an ^ anchor in both regexes, in case the file has foobar # this is a host – glenn jackman Feb 10 '14 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 '14 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 #. – Paul Nelson Baker Feb 11 '14 at 17:47
  • @SonofLysander yes, you're quite right, that was a mistake. Fixed now. – terdon Feb 11 '14 at 17:48
  • Cooool, thanks again for all your help. This has made changing my hosts file trivial :) – Paul Nelson Baker Feb 11 '14 at 18:06

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

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.