Reputation: 1131
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
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
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