ZakS
ZakS

Reputation: 1131

replace an exact match for a double underscore with a string using sed

I am trying to replace an exact match for a double underscore with a string.

sed -i 's/\<__\>/.abc.def__/g' file

But this leaves the file unchanged. Grateful for any pointers. follow up from Sed match exact

Upvotes: 1

Views: 577

Answers (2)

potong
potong

Reputation: 58351

This might work for you (GNU sed):

sed -E 's/^/\n/;:a;ta;s/\n__($|[^_])/.abc.def__\1\n/;ta;s/\n(_+|[^_]+)/\1\n/;ta;s/\n//' file

Prepend a newline to the current line.

Pattern match through the line using the newline as a delimiter.

If the pattern is matched, replace with the required string and step the delimiter over the replacement.

Otherwise, shift the delimiter along the line and repeat.

At the end of line, remove the introduced newline.


Alternative:

sed -E 's/(^|[^_])__($|[^_])/\1\n\2/g;s//\1\n\2/g;s/\n/.abc.def__/g' file

Upvotes: 1

Wiktor Stribiżew
Wiktor Stribiżew

Reputation: 626691

If you have no overlapping matches (and your provided input has none), a sed like this will do:

sed -E  's/([^_]|^)__([^_]|$)/\1.abc.def__\2/g' file > newfile

Here, ([^_]|^)__([^_]|$) matches and captures into Group 1 (\1) any char other than _ or start of string (([^_]|^)), then matches __, and then captures into Group 2 (\2) any char other than _ or end of string (([^_]|$)).

If there can be overlapping matches, sed becomes rather difficult to use here. A perfect alternative would be using

perl -pe 's/(?<!_)__(?!_)/.abc.def__/g' file > newfile
perl -i -pe 's/(?<!_)__(?!_)/.abc.def__/g' file

The (?<!_)__(?!_) regex contains two lookarounds, (?<!_) negative lookbehind that makes sure there is no _ char immediately to the left of the current location, and (?!_) negative lookahead makes sure there is no _ char immediately to the right of the current location.

See the online demo:

#!/bin/bash
s='AFM_7499_190512_110136_001_p_EQ4H_1_s60_0012__386___Day_'

sed -E  's/([^_]|^)__([^_]|$)/\1.abc.def__\2/g' <<< "$s"
# => AFM_7499_190512_110136_001_p_EQ4H_1_s60_0012.abc.def__386___Day_
perl -i -pe 's/(?<!_)__(?!_)/.abc.def__/g' <<< "$s"
# => AFM_7499_190512_110136_001_p_EQ4H_1_s60_0012.abc.def__386___Day_

Upvotes: 1

Related Questions