0

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.

user101
  • 175
  • 1
  • 10
  • 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 Sep 21 '16 at 19:57

3 Answers3

1

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 {
nu11p01n73R
  • 26,397
  • 3
  • 39
  • 52
  • I should mention that I'm actually searching for variables, so CAT is $CAT. This isn't finding and replacing anything in my file. Can that be why? I also tried with double quotes. – user101 Sep 21 '16 at 17:44
  • @user101 `$` has to be escaped as it has a special meaning to sed (end of pattern space): use `\$` – Benjamin W. Sep 21 '16 at 17:46
  • @BenjaminW. Not required if you are using double quotes. – nu11p01n73R Sep 21 '16 at 17:48
  • @user101 I tried something like `sed "s/^\([[:blank:]]*\)$test/\1DOG/"` which seems working on OSX. with `test=CAT` – nu11p01n73R Sep 21 '16 at 17:48
  • Ah, I might have misunderstood: either OP wants to replace `$CAT` with `$DOG` literally (`$` has to be escaped), or they want to use a shell variable in the sed command (can't use single quotes anyway). – Benjamin W. Sep 21 '16 at 17:50
  • @nu11p01n73R Still not working for me :( I've edited my post with the exact file and variables so you can try to replicate – user101 Sep 21 '16 at 18:29
  • Never surround a script with double quotes, always single. If you need to make part of the script accessible to the shell for interpretation, do it locally not globally, e.g. given a variable `cost="$50"` when you want to change the price in your file use `sed 's/'"$cost"'/$25/'`, not `sed "s/$cost/$25/"` to avoid surprises when you forget to escape characters (as I just did deliberately) and other issues. – Ed Morton Sep 21 '16 at 20:21
0

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
anubhava
  • 761,203
  • 64
  • 569
  • 643
0

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.

Community
  • 1
  • 1
Ed Morton
  • 188,023
  • 17
  • 78
  • 185