【问题标题】:Why is sed not replacing this newline character?为什么 sed 不替换这个换行符?
【发布时间】:2024-01-19 08:28:01
【问题描述】:

我在 Ubuntu 的 Bash shell 中使用 sed 来替换某些文件中的文本。这是我的文字:

 BLah </V>
<N> Blah

这是我想要转换的内容:

Blah" = "Blah

这是我正在使用的 sed 命令:

sed -i 's@ </V>\n<N> @" = "@g'

我所有的其他sed 命令都在工作,除了这个。这是唯一涉及换行符的搜索和替换情况。问题似乎是 \n 没有像我想的那样匹配换行符。

我的脚本哪里出错了?

【问题讨论】:

    标签: bash sed


    【解决方案1】:

    问题是sed 逐行处理文本。它的缓冲区中没有两条线(称为模式空间)。您可以通过调整脚本来修复它:

    sed 'N;s@ </V>\n<N> @" = "@g'
    

    来自man sed

       n N    Read/append the next line of input into the pattern space.
    

    这就是N 所做的:将下一行附加到模式空间。然后替换工作。

    例子:

    $ sed 'N;s@ </V>\n<N> @" = "@g' <<<' BLah </V>
    <N> Blah'
     BLah" = "Blah
    

    但是,这将有 50% 的可能性不起作用,具体取决于模式是从输入中的偶数行还是奇数行开始。为了解决这个问题,您可以像这样修改脚本:

    sed 'N;s@ </V>\n<N> @" = "@g;P;D'
    

    【讨论】:

    • 可能只是一个错字,但我认为您需要 -i 中的 sed 'N;s@ &lt;/V&gt;\n&lt;N&gt; @" = "@g' 才能使其成为 sed -i 'N;s@ &lt;/V&gt;\n&lt;N&gt; @" = "@g',否则它实际上不会执行更改。不过,除此之外,它就像一个魅力!谢谢!
    • @DaveMG 我个人只把-i放在最后一刻,从不用于测试;而且我的回答总是有可能会破坏某些东西,所以我倾向于省略-i以防万一:)
    • sed '/&lt;\/V&gt;/{N; s@ &lt;/V&gt;\n&lt;N&gt; @" = "@g}'
    • @aragaer 这也是一个不错的选择。不过,g 不是必需的。
    【解决方案2】:

    sed 是用于在单行上进行简单替换的出色工具,对于任何其他文本处理只需使用 awk:

    $ cat file
    Blah </V>
    <N> Blah
    
    $ awk -v RS= 'sub(/ <\/V>\n<N> /,"\" = \"")' file
    Blah" = "Blah
    

    没有这种保持模式、子空间中的传输缓冲区或任何需要的东西 - 只需将记录分隔符设置为换行符以外的其他内容,并将多行字符串视为任何其他字符串。

    【讨论】: