Issue with sed command does not replace exact string matched

I have a file change.sed
more change.sed

I fire the below command inorder to replace "190.169.11.15" with "10.4.112.240" in proxy.log

sed -f change.sed proxy.log

proxy.log has the below entry
more proxy.log

The command replaces both 190.169.11.15 & 190.169.11.155 as below:

I am expecting 190.169.11.155 should not be replaced i.e if there is any extra numeric digit after the search string i.e '5' (190.169.11.155) in this case then the replace action should not happen.

bash-3.2$ uname -a
SunOS mymac 5.10 Generic_Virtual sun4v sparc sun

Can you please help.

There are two problems with your regex. "." is a special character meaning "any single character", ergo, the regex "192.168.0.126" would also match "1912168Q0126"!

Fixing your particular problem depends on having a modern enough sed it supports extended regexes and backreferences.

I usually do something like this:

$ echo "word stuff 0.0.0.1 0.0.0.10 0000001 0.0.0.1" | sed 's#\(^\| \)0[.]0[.]0[.]1\($\| \)#\19.9.9.9\2#g'

word stuff 9.9.9.9 0.0.0.10 0000001 9.9.9.9

$

The red (^| ) matches either "beginning of the line" or "space", and the red \1 - just as importantly - puts it back in the output. The green does the same for end-of-line or space. Matching [.] between numbers forces it to take the . literally. '\.' probably also works but strikes me as harder to read.

1 Like

one way - not fool-proof:

s=190.169.11.15 =10.4.112.240 =g

I wish to use sed -f . Also, if you can ignore the decimal issue will you be able to tell me how the simplified sed would look like where it ignore matching strings immediately followed by a numeric digit ?

---------- Post updated at 12:03 PM ---------- Previous update was at 12:00 PM ----------

Sorry, i am not looking for this solution as my command runs across thousands of files. It may encounter an IP followed by any character which i m not sure.

Hence i m looking to ignore the sed whenever the matching string is followed by a numeric digit else the sed should do the replacement action..

Then I would suggest putting the regex into a file.

I did but it is failing as below:

more change.sed

Command with error output:

sed -f change.sed proxy.log
Unrecognized command: 's=\(^\| \)190.169.11.15\($\| \)=\1110.4.112.240\2=g'

Remove the 'single quotes'

Error is gone but it Did not help. Nothing got replaced when I was expecting the first (..its 190.169.11.15 c..) and third (.. >190.169.11.15< ...) occurrences of 190.169.11.15 to get replaced and only the second one (... 190.169.11.155 ...)should have been ignored.

more proxy.log

more change.sed

command: sed -f change.sed proxy.log

That it worked partially is very strange. Show the input you had, the output you were expecting, the output you got, and the exact code and regex file you used.

Input or original file proxy.log

Expected output:

as you can see only 2/3 string "190.169.11.15" should be replaced.

The one which should not get replaced is 190.169.11.155 because it is followed by / preceded by a numeric digit(see red bold)

Current i am getting the below output:

As you can see nothing got replaced :frowning:

more change.sed

s=\(^\| \)190.169.11.15\($\| \)=\110.4.112.240\2=g

My command is sed -f change.sed proxy.log

Ah, I think I see:

I specified "beginning of line or space", not "beginning of line, space, or >". I can specify "beginning of line or non-numeric", "end of line or non-numeric" instead.

How about:

s=\(^\|[^0-9]\)190.169.11.15\($\|[^0-9]\)=\110.4.112.240\2=g

This also does not work. It does not replace anything. See output:

echo " logs for the >190.169.11.15< instances on various nodes. If there 190.169.11.1555 are no instan" | sed 's=\(^\|[^0-9]\)190.169.11.15\($\|[^0-9]\)=\110.4.112.240\2=g'
 logs for the >190.169.11.15< instances on various nodes. If there 190.169.11.1555 are no instan

You have sneak-edited in more details now but it should have had them in the first place.

It works perfectly with the input you gave me, I get

including its 10.4.112.240 configuration, runtime artifacts 190.169.11.155 such as >10.4.112.240< lock databases.

Show exactly how you used it down to the last keystroke.

I am sharing the snapshot so there is no doubt


CLICK HERE to see SNAPSHOT

Your reports are inconsistent. It's possible that your version of sed doesn't support the extended syntax -- but then it shouldn't ever have worked at all, not just missed a few things inside >< brackets.

Do you have GNU sed on your system? (gsed) Or perl?

I do have perl but I usually avoid perl as I m not at all familiar. Also perl is less likely to be on every server I use my scripts as compared to sed .

bash-3.2$ file /usr/xpg4/bin/sed
/usr/xpg4/bin/sed:      ELF 32-bit MSB executable SPARC Version 1, dynamically linked, stripped
bash-3.2$ which sed
/usr/bin/sed
bash-3.2$ gsed
bash: gsed: command not found

I tried using /usr/xpg4/bin/sed however, does not replace the strings either.

How about awk?

awk '{for (i=1; i<=NF; i++) if ($i==from) $i=to; print}' from=190.169.11.15 to=10.4.112.240 < proxy.log

Or

cat changefile
190.169.11.15 10.4.112.240

awk 'FILENAME!="-" {A[$1]=$2; next} {for (i=1; i<=NF; i++) if (A[$i]!="") $i=A[$i]; print}' changefile - < proxy.log

The (A[$i]!="") is clumsy and can consume extra memory but supports Solaris /bin/awk.
Better is ($i in A) . Then Solaris needs nawk or /usr/xpg4/bin/awk
You can add more lines to changefile...

1 Like