0
votes

Say my search term is CAT, replace term is DOG I only want to match things that begin with whitespace before CAT, regardless of how much whitespace. Also, is there any way I can preserve the correct amount of whitespace?

so

else CAT {

would stay

else CAT {

but

CAT {

would become

DOG {

and

                  CAT {

would become

                  DOG {

I am trying sed -i ' ' -E "s/^[^a-z]*CAT/DOG/g" $file so that it doesn't match anything that has letters anywhere between the beginning of the line, and the search term

And other variations, but haven't found anything that works correctly. I can't do sed -i ' ' -E "s/^[ \t]*CAT/DOG/g" $file because \t doesn't work on OSX

---- my file:

method()
{   
    if ((self = [super init])) {
        hello1
    }

    else if ((self = [super init])) {
        hello2
    }
}

---- using sed -i '' "s/^\([[:blank:]]*\)$s/\1$r/" $file

Turns it into:

method()
{   
    self = [super init];
    if (self) {
        hello1
    }


    if () {
        hello2
    }
}

which is bad, because I don't want the second else if to be affected at all. The first one is good though.

3
You say "which is bad..." at the end but you're missing the most important parts which is to show us what is good output and the regexp stored in $s that you are trying to find and replacement in $r. - Ed Morton

3 Answers

1
votes

You can use a character class with capture group as

sed 's/^\([[:blank:]]*\)CAT/\1DOG/'
  • \([[:blank:]]*\) Matches zero or more white spaces and capture them in group 1, \1.

Example

$ echo "                  CAT {" | sed 's/^\([[:blank:]]*\)CAT/\1DOG/'
                  DOG {
0
votes

You can use capturing group for whitespaces:

sed -i ' ' -E 's/^([[:blank:]]*)CAT/\1DOG/' file

There is no need to use g flag since we are replacing at the start only once.

If you want to use variables then use double quotes:

s='CAT'
r='DOG'
sed -i '' -E "s/^([[:blank:]]*)$s/\1$r/" file
0
votes

It's pretty unclear from your question but maybe this is what you want:

$ cat tst.sh
old='if ((self = [super init])) {'
awk -v old="$old" '
BEGIN {
    new = old
    gsub(/.*\(|\).*/,"",new)
    new = new ";"
}
start=index($0,old) {
    before = substr($0,1,start-1)
    after  = substr($0,start+length(old))
    if (before ~ /^[[:space:]]*$/) {
        $0 = before new after
    }
}
{ print }
' file

$ ./tst.sh
method()
{
    self = [super init];
        hello1
    }

    else if ((self = [super init])) {
        hello2
    }
}

Note that you can just construct the replacement text on the fly and because its using literal strings instead of regexp and backreference-enabled-string operations you don't need to escape anything in either the string you are searching for or its replacement (except backslashes - we can tweak that to fix if you need it).

If you had been considering using sed for this or using *sub() or match() in awk then read Is it possible to escape regex metacharacters reliably with sed first.