sed的多行下一行(N)是否有限制?

时间:2014-04-30 13:25:50

标签: regex bash sed

我使用sed来匹配多行。

me@CYGWIN:$ cat foo.txt
Click on <menucascade>
        <uicontrol>File</uicontrol>
        <uicontrol>Save</uicontrol>
        <uicontrol>Options</uicontrol>
        <uicontrol>PDF</uicontrol>
</menucascade>.

我想要sed:

  1. 查找menucascade标记。
  2. 将以下uicontrol标记更改为b标记。
  3. 添加&gt;到最后一行。
  4. 仅当uicontrol进入菜单级别时才这样做(而不是 任何其他时间)。
  5. 如果我知道使用uicontrol的次数,我可以使用N将下一行添加到模式空间:

    me@CYGWIN:$ sed '/<menucascade>/{N;N;N;N; s/<uicontrol>\([^<]*\)<\/uicontrol>/<b>\1<\/b>\ >/g}' foo.txt
    Click on <menucascade>
            <b>File</b> >
            <b>Save</b> >
            <b>Options</b> >
            <b>PDF</b> >
    </menucascade>.
    

    但是,如果我不知道使用uicontrol的次数(因此不知道要添加的N的数量),该怎么办?在Cygwin上,sed似乎在5 N之后最大化。因此,如果我高估并且投入超过5个N,它根本不起作用。

    me@CYGWIN:$ sed '/<menucascade>/{N;N;N;N;N;N; s/<uicontrol>\([^<]*\)<\/uicontrol>/<b>\1<\/b>\ >/g}' foo.txt
    Click on <menucascade>
            <uicontrol>File</uicontrol>
            <uicontrol>Save</uicontrol>
            <uicontrol>Options</uicontrol>
            <uicontrol>PDF</uicontrol>
    </menucascade>.
    

    首先:任何人都可以解释为什么sed脚本无法与6个N匹配?

    第二:任何人都可以建议如何使用sed在menucascade中匹配n个uicontrol实例?或者,如果sed是错误的工具,任何人都可以建议一个在bash脚本中工作的替代方法吗?

    感谢。

1 个答案:

答案 0 :(得分:0)

您可以根据需要多次使用N,但是(来自POSIX):

  

如果没有下一行输入可用,则N命令动词应分支到脚本的末尾

因此,如果只是不小心使用它们,最终它们会导致你的脚本结束。

POSIX也不保证模式空间中超过8192个字节,但你可能正在使用支持更多方式的GNU sed。

正确的方法是使用像xmlstarlet这样的xml工具,虽然这假设你至少使用了xhtml的外观:

$ cat foo.xml
<html>
    <h1>Blah</h1>
    <p>
      Click on <menucascade>
      <uicontrol>File</uicontrol>
      <uicontrol>Save</uicontrol>
      <uicontrol>Options</uicontrol>
      <uicontrol>PDF</uicontrol>
      </menucascade>
    </p>
    <p>
      <uicontrol>Other stuff</uicontrol>
    </p>
</html>

然后

$ xmlstarlet ed -r "//menucascade/uicontrol" -v b foo.xml
<?xml version="1.0"?>
<html>
  <h1>Blah</h1>
  <p>
      Click on <menucascade><b>File</b><b>Save</b><b>Options</b><b>PDF</b></menucascade>
    </p>
  <p>
    <uicontrol>Other stuff</uicontrol>
  </p>
</html>