41

In a file containing lines like this one:

# lorem ipsum blah variable

I would like to remove # (comment) character in the same line that contains a specific string, in place. Is sed good for this?

I'm struggling to get this conditional working. I have a "clumsy" way of doing this; I can find the matching line number with awk or sed and then use this number in a separate sed command, but I believe that this can be done in a much better way.

slm
  • 369,824
Kamil
  • 1,461

4 Answers4

74

Use the string you are looking for as the selector for the lines to be operated upon:

sed '/ipsum/s/#//g'

/ipsum/ selects lines containing "ipsum" and only on these lines the command(s) that follow are executed. You can use braces to run more commands

/ipsum/{s/#//g;s/@/-at-/g;}
peterph
  • 30,838
  • 4
    I agree; this is the best answer (although not the only one). Comments: (1) 's/#//g' will remove all the # characters in the line. If that’s not what you want, remove the g (which stands for “global”). (2) To edit a file in place (as asked for in the question), use sed -i. – G-Man Says 'Reinstate Monica' Sep 12 '14 at 21:54
  • 2
    (3) As a matter of real-world situations, if you want to un-comment a line, you might want to use sed -i '/ipsum/s/#[[:space:]]*//', to get rid of any spaces and tabs immediately following the #. (4) You might also want to consider verifying that the # is the first non-blank character in the line. The current command would delete the # from the line prompt "Enter # of ipsums:". – G-Man Says 'Reinstate Monica' Sep 12 '14 at 21:55
  • @G-Man feel free to update the answer - it's a community one, so it shouldn't require review with your reputation. – peterph Sep 13 '14 at 12:35
  • 2
    @G-Man - great addition! To your 2nd pt (leading space), what about: sed -i '/ipsum/s/^#[[:space:]]*//'?! (^ signifies start of line, $ for end of line) - at least in gnu sed... – Jeremy Davis Oct 19 '17 at 06:02
  • 1
    @JeremyDavis: Yes, you *could* anchor the regex to the beginning of the line with ^, but that would be wrong. I often comment out indented code by putting the # immediately before the code, so the # is indented.  I doubt that I’m the only person who does that. – G-Man Says 'Reinstate Monica' Oct 21 '17 at 03:50
  • 1
    @G-Man - ah yes, of course! Thanks, I hadn't considered that. So you'd also want to check for whitespace between ^ & #, so something more like this: /ipsum/{/^[[:space:]]*#/s/#[[:space:]]*//}. Although even then, depending on where the # is, it may still cause issues (e.g. in languages that use whitespace indentation/separation). – Jeremy Davis Oct 22 '17 at 00:04
9
$ cat input.txt
# lorem ipsum blah variable
# lorem ipsum blat variable
# lorem ipsum blow variable
# lorem ipsum blip variable
# lorem ipsum blue variable

then:

$ sed 's|# \(.*blue.*\)|\1|' input.txt

gives:

# lorem ipsum blah variable
# lorem ipsum blat variable
# lorem ipsum blow variable
# lorem ipsum blip variable
lorem ipsum blue variable

It works as follows:

The s tells sed that it should substitute what the regular expression finds.

The pattern is # \(.*blue.*\) which breaks down to: Find a hash followed by a space. The bracket (\() starts the grouping. .*blue.* is the word blue with anything before and after. The next bracket (\)) closes the grouping.

The replacement is \1 which is a back-reference to the content of the first grouping bracket.

garethTheRed
  • 33,957
3

You can use the POSIX tool ex:

ex a.txt <<eof
/Sunday/ sub/Sun//
xit
eof

https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ex.html

Zombo
  • 1
  • 5
  • 44
  • 63
  • That's pretty cool. I didn't know about that! TBH, I'm not sure it's the best answer for this question (IMO the leading sed answer is the one) but it's still very cool! Thanks for posting. – Jeremy Davis Oct 19 '17 at 05:55
2

You can do this as follows.

sed '/ipsum/s/^# //g'

This matches all lines containing ipsum and removes the comment from the beginning of the line. ^ matches the beginning of the line and $ matches the end. The rest of the command uses the syntax sed 's/find/replace/g' and can be called to edit a file as sed -i '/ipsum/s/^# //g' file.

You can reverse this as follows:

sed '/ipsum/s/^/# /g'

This will add a comment to the beginning of each line containing ipsum.

Tom Kelly
  • 797