使用sed,如何进一步改造group back references?
Using sed, how can group back references be further transformed?
我可以使用 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 \([^)]*\))||' <<<"com.xyz (@ -p com.abc) com.pqr (@ -p com.ghi)"
com.xyz com.abc com.pqr com.ghi
这会进行适当的选择;但是,现在我仍然需要用 s|\.|_|g
.
转换
部分
任何人都可以展示如何使用 sed 完成此操作吗?
我的环境是 bash 4.2.46(1)-release, CentOS 7.3.1611.
备注:
- 我正在将其添加到现有的 sed 脚本中,因此我非常喜欢 sed 解决方案,而不是将当前 sed 脚本的结果通过管道传输到另一个字符串处理器(例如 awk)。如果这个问题没有sed的解决方案,那么接下来我会考虑awk的解决方案。
- 我的问题特定于上例中显示的模式。
您可以使用 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
gawk 解决方案:
str="com.xyz (@ -p com.abc.def) com.pqr.stu"
awk 'match([=10=], /\(@ -p ([^)]+)\)/, a){ "echo "a[1]" | tr \".\" \"_\"" | getline v;
sub(/\(@ -p ([^)]+)\)/,v, [=10=]); print }' <<< $str
输出:
com.xyz com_abc_def com.pqr.stu
如果目标字符串只出现一次(每行输入),
你可以使用 hold space 来做双重替换,像这样:
单个替换
#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 \([^)]*\)).*//
#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\(.*\)(@)//
示例输出:
%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 \([^)]*\)).*//
#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\(.*\)(@)//
#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
硬化
更可靠的版本可能使用换行符作为 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\n/1
#Strip off anything except the target substring value: B -- A\nC
s/.*\n(@ -p \([^)]*\))\n.*//
#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//
#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
我可以使用 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 \([^)]*\))||' <<<"com.xyz (@ -p com.abc) com.pqr (@ -p com.ghi)"
com.xyz com.abc com.pqr com.ghi
这会进行适当的选择;但是,现在我仍然需要用 s|\.|_|g
.
部分
任何人都可以展示如何使用 sed 完成此操作吗?
我的环境是 bash 4.2.46(1)-release, CentOS 7.3.1611.
备注:
- 我正在将其添加到现有的 sed 脚本中,因此我非常喜欢 sed 解决方案,而不是将当前 sed 脚本的结果通过管道传输到另一个字符串处理器(例如 awk)。如果这个问题没有sed的解决方案,那么接下来我会考虑awk的解决方案。
- 我的问题特定于上例中显示的模式。
您可以使用 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
gawk 解决方案:
str="com.xyz (@ -p com.abc.def) com.pqr.stu"
awk 'match([=10=], /\(@ -p ([^)]+)\)/, a){ "echo "a[1]" | tr \".\" \"_\"" | getline v;
sub(/\(@ -p ([^)]+)\)/,v, [=10=]); print }' <<< $str
输出:
com.xyz com_abc_def com.pqr.stu
如果目标字符串只出现一次(每行输入), 你可以使用 hold space 来做双重替换,像这样:
单个替换
#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 \([^)]*\)).*//
#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\(.*\)(@)//
示例输出:
%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 \([^)]*\)).*//
#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\(.*\)(@)//
#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
硬化
更可靠的版本可能使用换行符作为 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\n/1
#Strip off anything except the target substring value: B -- A\nC
s/.*\n(@ -p \([^)]*\))\n.*//
#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//
#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