我可以使用 sed 将正则表达式匹配替换为正则表达式中组后向引用的转换吗?
问题
假设我想替换表单的字符串:
(@ -p <fqdn>)
每行可能有多个这样的匹配。
使用:
<fqdn with dots replaced by underscores>
示例
com.xyz (@ -p com.abc.def) com.pqr.stu (@ -p com.ghi)
会变成:
com.xyz com_abc_def com.pqr.stu com_ghi
观
要开始寻求解决方案,请考虑:
$ sed 's|(@ -p \([^)]*\))|\1|' <<<"com.xyz (@ -p com.abc) com.pqr (@ -p com.ghi)"
com.xyz com.abc com.pqr com.ghi
这是适当的选择;但是,现在我仍然需要使用\1
转换s|\.|_|g
部分。
有人能说明如何使用sed完成这项工作吗?
我的环境是bash 4.2.46(1)-release,CentOS 7.3.1611。
备注:
答案 0 :(得分:3)
如果目标字符串仅出现一次(每行输入), 您可以使用保留空间进行双重替换,如下所示:
#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/
示例输出:
%echo "com.xyz (@ -p com.abc) com.pqr" | sed -f doublereplace.sed
com.xyz com_abc com.pqr
循环版本如下所示:
#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
}
示例输出:
%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
更可靠的版本可能会使用换行符作为分隔符/标记字符串:
#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
}
这将允许输入数据中任何不完整的@()
构造,
比如(@ 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
答案 1 :(得分:2)
您可以使用gnu awk
:
s='com.xyz (@ -p com.abc.def) com.pqr.stu'
awk -v RS='\\(@ -p [^)]+\\)' '{
ORS=gensub(/.* |\)/,"","g",gensub(/\./,"_","g",RT))} 1' <<< "$s"
com.xyz com_abc_def com.pqr.stu
答案 2 :(得分:0)
gawk 解决方案:
str="com.xyz (@ -p com.abc.def) com.pqr.stu"
awk 'match($0, /\(@ -p ([^)]+)\)/, a){ "echo "a[1]" | tr \".\" \"_\"" | getline v;
sub(/\(@ -p ([^)]+)\)/,v, $0); print }' <<< $str
输出:
com.xyz com_abc_def com.pqr.stu