2

This question already has an answer here:

I've looked at some other questions related to using sed to replace strings, but I'm having trouble figuring out how to apply it to my particular need.

In a case like the snippet below, I want to change the string only on lines that do not begin with a "#":

    #####################################
    # Blah blah blah string blah blah
    #####################################

    PKG_NAME="string"
    PKG_DESC="string-foo"

I would like the output to read like this:

    #####################################
    # Blah blah blah string blah blah
    #####################################

    PKG_NAME="newString"
    PKG_DESC="newString-foo"

From what I have gathered, I think I can use find and sed to change all of the strings in all of the files

find . -type f -exec sed -i 's/string/newString/g' {} +

But I am just having trouble figuring out how to add an exception for lines beginning with "#". I'm open to other ways of doing this other than sed, so if there is an easier way please feel free to share.

After reading How to only substitute lines that match several patterns in sed?, I see how to change a string in cases where a line starts with a certain pattern, but what I need is to change lines where the pattern is not found.

marked as duplicate by jasonwryan, Braiam, don_crissti, roaima, Stephen Kitt Aug 25 '15 at 21:38

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • I'm not sure if that answers my question, or perhaps I'm too thick to see it (also possible...). I need to skip lines that match a pattern, rather than look for and change lines that fit the pattern. – Geoff Aug 25 '15 at 19:17
  • Read Stephane anwers. – Braiam Aug 25 '15 at 19:20
3

You want to change these "string"s which are in lines where there are no # character or this character is after "string", so that you can have comments at the end of the lines:

#####################################
# Blah blah blah string blah blah
#####################################

PKG_NAME="string"
PKG_DESC="string-foo"
PKG_A="string" # this is comment after string

In order to this properly run

sed 's/^\([^#]*\)string/\1newString/' file

Result:

#####################################
# Blah blah blah string blah blah
#####################################

PKG_NAME="newString"
PKG_DESC="newString-foo"
PKG_A="newString" # this is comment after string
  • Interesting! I think I will mark this as the answer as it works much more generally. I wasn't initially worried about comments after the string for this particular case, but I can see this solution being much more valuable in the long run. – Geoff Aug 25 '15 at 19:39
3

In sed you can stop doing actions if a pattern is found with an exclamation mark:

sed '/#/!s/string/replacement/' file

I.e. for lines matching '#' (at any position) do not do the replacement - else do. In your case result is:

#####################################
# Blah blah blah string blah blah
#####################################

PKG_NAME="replacement"
PKG_DESC="replacement-foo"

For skipping only lines that begin with hash, change the regex to:

sed '/^#/!s/string/replacement/' file

Note that lines with comments at the end of the line will have the changes applied to the commented part, too, while in the upper example these lines would not be changed at all (including the code part).

  • 1
    /#/ is cool trick, but it doesn't replace "string" if # is present at the end of the line (as a comment). – jimmij Aug 25 '15 at 19:32
  • correct, should better be /^#/ for beginning of line only (as explicitly requested by OP in his question) – Fiximan Aug 25 '15 at 19:39
  • 1
    there can be spaces in front of # too. – jimmij Aug 25 '15 at 19:46
  • well, /^ \{0,\}#/ would match that. But I agree, excluding all comments no matter where on a line is more general. – Fiximan Aug 25 '15 at 19:49

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