Issue
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
Solution
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_
Answered By - Wiktor Stribiżew Answer Checked By - Cary Denson (WPSolving Admin)