跨多行进行 SED 替换

跨多行进行 SED 替换

我正在尝试找到以下三行:

<!--
<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

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

答案1

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

答案2

Sed 是逐行工作的。它可以在多行上工作,但它不是这样设计的 - 在我看来,当你尝试这样使用时,它肯定会显示出来。但如果你决定这样做,你可能不得不使用寄存器。查看一些解决方案https://stackoverflow.com/questions/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

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

改编自:

https://stackoverflow.com/questions/1030787/multiline-search-replace-with-perl

答案3

以下是 SED 中多行命令的描述:http://docstore.mik.ua/orelly/unix/sedawk/ch06_01.htm

这真是太麻烦了。您可能想听从 Eduardo 的建议,改用它perl -i -p -e

答案4

  • /<\!--/:匹配字符串
  • :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

相关内容