If the target string only occurs once (per line of input),
you can use the hold space to do the double replacement, like this:
Single replacement
#Copy input line to the hold space: A(@B)C -- A(@B)C
h
#Replace the target substring with (@) (a "marker" string): A(@)C -- A(@B)C
s/(@ -p [^)]*)/(@)/
#Exchange the content of the pattern space and hold space: A(@B) -- A(@)C
x
#Strip off anything except the target substring value: B -- A(@)C
s/.*(@ -p \([^)]*\)).*/\1/
#Modify the target substring as appropriate: B' -- A(@)C
y/./_/
#Append the content of the hold space back to the pattern space: B'\nA(@)C --
G
#Merge the lines, replacing the "marker" string with the processed value: AB'C
s/\(.*\)\n\(.*\)(@)/\2\1/
Sample output:
%echo "com.xyz (@ -p com.abc) com.pqr" | sed -f doublereplace.sed
com.xyz com_abc com.pqr
Multiple replacements
The looped version will look like this:
#Loop label
:start /(@/ {
#Copy input line to the hold space: A(@B)C -- A(@B)C
h
#Replace the target substring with (@) (a "marker" string): A(@)C -- A(@B)C
s/(@ -p [^)]*)/(@)/
#Exchange the content of the pattern space and hold space: A(@B) -- A(@)C
x
#Strip off anything except the target substring value: B -- A(@)C
s/[^(]*(@ -p \([^)]*\)).*/\1/
#Modify the target substring as appropriate: B' -- A(@)C
y/./_/
#Append the content of the hold space back to the pattern space: B'\nA(@)C --
G
#Merge the lines, replacing marker string with the processed value: AB'C
s/\(.*\)\n\(.*\)(@)/\2\1/
#Loop
b start
}
Sample output:
%echo "com.xyz (@ -p com.abc.def) com.pqr.stu (@ -p com.ghi)" |
sed -f doublereplace.sed
com.xyz com_abc_def com.pqr.stu com_ghi
Hardened
A bit more reliable version might use newlines as separators/marker string:
#Loop label
:start /(@ -p [^)]*)/ {
#Copy input line to the hold space: A(@B)C -- A(@B)C
h
#Replace the target substring with (@) (a "marker" string): A\nC -- A(@B)C
s/(@ -p [^)]*)/\n/
#Exchange the content of the pattern space and hold space: A(@B)C -- A\nC
x
#Isolate the first instance of a target substring to a separate line A\n(@B)\nC -- A\n\C
s/\((@ -p [^)]*)\)/\n\1\n/1
#Strip off anything except the target substring value: B -- A\nC
s/.*\n(@ -p \([^)]*\))\n.*/\1/
#Modify the target substring as appropriate: B' -- A\nC
y/./_/
#Append the content of the hold space back to the pattern space: B'\nA\nC --
G
#Merge the lines, replacing marker string with the processed value: AB'C
s/\(.*\)\n\(.*\)\n/\2\1/
#Loop
b start
}
That will allow for any incomplete @()
constructs in the input data,
like (@ t.i.m.e.s)
:
%echo "com.xyz (@ -p com.abc.def) fails (@ t.i.m.e.s) com.pqr.stu (@ -p com.ghi)" |
sed -f doublereplace.sed
com.xyz com_abc_def fails (@ t.i.m.e.s) com.pqr.stu com_ghi