SED跨多行替换


11

我试图找到这三行:

<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->

并替换为:

<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

当我尝试

sudo sed -i 's:<!-- <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

它找不到它,我也尝试将\ n放入其中,但仍然无法正常工作:

sudo sed -i 's:<!--\n <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />\n -->:<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />:' /myfile.xml

这些不会引发任何错误,只是不会取消注释。任何建议将帮助谢谢!

Answers:


6

sed会依次读取每一行,因此除非您向正确的方向轻推,否则它永远不会匹配多行模式。该N命令从输入中读取一行并将其追加到模式空间。

sed -i -e '/^<!--$/ {
    N; /\n<Connector port="8009" protocol="AJP\/1\.3" redirectPort="8443" \/>$/ {
        N; /\n-->$/ {
            s/^<!--\n//; s/\n-->$//
        }
    }
}' /myfile.xml

可以说,如果需要除以外的命令s,则应从sed切换到awk或perl。这是一个稍微灵活一些的Perl代码段,可以更一般地处理多行注释。

perl -i -pe '
    if (/<!--/) { $_ .= <> while !/-->/;
        s[<!--\n(<Connector port="8009" protocol="AJP/1\.3" redirectPort="8443" />)\n-->][$1];
    }' /myfile.xml

6

Sed逐行工作。可以使它在多行上工作,但是它并不是那样设计的-我认为它一定会在您尝试使用时显示出来。但是,如果您决定采用这种方式,则可能必须使用寄存器。查看/programming/1251999/sed-how-can-i-replace-a-newline-n的一些解决方案,以了解如何实现。

我更喜欢使用perl而不是sed来完成此类任务(我是指面向多行)。您在搜索和替换(BEGIN...)之前必须添加的样板并不明显,但是正则表达式对我而言似乎更干净:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--string-->/string/smg' file.xml

或者,使用分组来缩短表达式并允许您在其中使用正则表达式:

perl -i.bak -pe 'BEGIN{undef $/;} s/<!--(string_or_regex)-->/\1/smg' file.xml

它应适用于注释标记与要取消注释的代码之间带有换行符和不带有换行符的情况。

改编自:

/programming/1030787/multiline-search-replace-with-perl


谢谢您的帮助,看起来好像很痛苦,我决定使用一种解决方法
Doug Molineux


1
  • /<\!--/ :匹配字符串
  • :X :这是分支命令“ b”的标签
  • /-->/ :匹配字符串
  • s@...@...@p :剥离“ <!-”,“->”并打印结果
  • d :删除模式空间并开始新的循环
  • N :如果与/-> /不匹配,则添加一行
  • bX :分支到:X标签
  • p :仅打印与/ <!-/不匹配的字符串

sed -rn '
/<!--/ {
    :X
    /-->/ {
        s@<!--\s*(<.+/>)\s*-->@\1@p
        d
    }
    N
    bX
};p'

第二种方法是用简单的复制和逐字记录替换通常的小型文本文件(需要shell脚本文件)

#!/bin/bash

# copy & paste content that you want to substitute

AA=$( cat <<\EOF | sed -z -e 's#\([][^$*\.#]\)#\\\1#g' -e 's#\n#\\n#g'
<!--
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
-->
EOF
)

BB=$( cat <<\EOF | sed -z -e 's#\([&\#]\)#\\\1#g' -e 's#\n#\\n#g'
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />
EOF
)

sed -z -i 's#'"${AA}"'#'"${BB}"'#g' *.xml   # apply to all *.xml files

1)谢谢您的回答。2)仅插入代码段并不是一件好事,如果您能解释它的作用和方式,那会更好。
peterh-恢复莫妮卡
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.