使用sed,如何进一步转换组引用?

时间:2017-08-11 08:24:07

标签: bash awk sed replace centos7

我可以使用 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。

备注:

  • 我将此添加到现有的sed脚本中,所以我更喜欢sed解决方案,而不是将当前sed脚本的结果传递给另一个字符串处理器,例如awk。如果没有这个问题的解决方案,那么接下来我会考虑awk解决方案。
  • 我的问题特定于上例中显示的模式。

3 个答案:

答案 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