【问题标题】:parsing and replacing multiple lines with sed用 sed 解析和替换多行
【发布时间】:2025-11-29 09:20:36
【问题描述】:

我正在尝试用 sed 替换 3 行的块,但遇到了一个奇怪的问题……我正在使用的脚本是

/^#begin$/N;N;s/#begin\n\(.*\)\n#end/replaced \1/

在看起来像这样的输入文件上

#begin
1
#end

它工作正常,我明白了

replaced 1

但是,如果在块之前有一行,则解析失败……应用相同的脚本

a line
#begin
1
#end

不会改变任何东西。如果我添加两行(比如说“一行”,然后是“另一行”),它会再次起作用……我不明白为什么。 有什么想法吗?

谢谢!

【问题讨论】:

    标签: sed


    【解决方案1】:

    在特定模式的操作周围使用{ .. }

    /^#begin$/{N;N;s/#begin\n\(.*\)\n#end/replaced \1/}
    

    例如:

    $ cat file
    a line
    #begin
    1
    #end
    

    $ sed '/^#begin$/{N;N;s/#begin\n\(.*\)\n#end/replaced \1/}' file
    a line
    replaced 1
    

    sed (BSD) 的某些版本要求在结束大括号前添加一个尾随 ;。所以使用以下内容:

    sed '/^#begin$/{N;N;s/#begin\n\(.*\)\n#end/replaced \1/;}' file
    

    【讨论】:

    • 我试过了,但是如果我添加这些脚本会中断并出现错误“替代命令中的错误标志:'}'”
    • 您使用的是哪个版本的sed?什么OS?您可能需要在右大括号之前添加一个尾随 ;
    • 这是在 Mac OSX 10.7.5 上,由于某种原因我无法找到版本……“-v”和“--version”失败。但尾随的“;”成功了,非常感谢!我也刚刚编译了 sed 4.2.1,它接受没有尾随“;”的“}”。
    • @user3692103 不客气。没错,sedBSD 变体需要一个尾随;。将其添加到答案中,因为它有帮助。
    【解决方案2】:

    对于涉及多行的任何事情,最好使用 awk。例如,使用 GNU awk 进行多字符 RS 和 gensub():

    $ gawk -v RS='^$' -v ORS= '{$0=gensub(/#begin\n([^\n]+)\n#end/,"replaced \\1","")}1' file
    a line
    replaced 1
    

    【讨论】:

    • 在这种特殊情况下,我必须使用 sed 来完成。使用括号解决了问题
    【解决方案3】:

    这可能对你有用(GNU sed):

    sed '/#begin/,/#end/c\replaced 1' file
    

    【讨论】:

    • 好吧,我发布的示例是一个简化版本,实际上在开始和结束标记之间有一些需要特殊处理的东西。上面提出的支架解决方案可以很好地解决这个问题。
    最近更新 更多