【问题标题】:Search and replace accross multiple lines in large files在大文件中跨多行搜索和替换
【发布时间】:2014-02-03 11:11:35
【问题描述】:

我想在大文件(大约 900 MB)中搜索和替换。我在网上搜索了几个小时。

一般来说有两种适合的工具,sed 和 perl。
sed 的多行语法似乎很复杂,所以我尝试了 perl。

我的输入数据如下所示:

K 13
svn:mergeinfo
V 498
/code/branches/TEST_ENVIRONMENT_OBC/Implementation//SpecificComponents/SUV/config/TEST:4670-4976
/code/tags/QR_20131111/Implementation/SpecificComponents/SUV/config/TEST:4669
/code/tags/QR_20131211/Implementation/SpecificComponents/SUV/config/TEST:5138
/code/trunk/Implementation/SpecificComponents/SUV/config/OBC:4669-4949
/code/trunk/Implementation/SpecificComponents/SUV/config/TEST:5137-5273
PROPS-END

我想更改 svn:mergeinfo 块并替换部分路径。
所以我为 perl 写了一个小的正则表达式。

perl -0pe 's/^svn:mergeinfo\nV (\d+)\n(?:\/code(\/(?:branches|tags|trunk)(?:.|\n)+))+\nPROPS-END/svn:mergeinfo\nV \1\n\2\nPROPS-END/m'

到目前为止它工作正常,但输出数据中的路径仅在第一次出现时更改。

K 13
svn:mergeinfo
V 498
/branches/TEST_ENVIRONMENT_OBC/Implementation//SpecificComponents/SUV/config/TEST:4670-4976
/code/tags/QR_20131111/Implementation/SpecificComponents/SUV/config/TEST:4669
/code/tags/QR_20131211/Implementation/SpecificComponents/SUV/config/TEST:5138
/code/trunk/Implementation/SpecificComponents/SUV/config/OBC:4669-4949
/code/trunk/Implementation/SpecificComponents/SUV/config/TEST:5137-5273
PROPS-END

我需要更改什么来替换所有出现的路径?

不需要使用perl来解决问题。

【问题讨论】:

    标签: regex perl sed


    【解决方案1】:

    你可以使用sed:

    sed -r '/svn:mergeinfo/,/PROPS-END/{s#(/code)(/(branches|tags|trunk))(.*)#\2\4#}' inputfile
    

    这将在匹配模式svn:mergeinfoPROPS-END 的行之间执行替换。

    对于您的输入,结果是:

    K 13
    svn:mergeinfo
    V 498
    /branches/TEST_ENVIRONMENT_OBC/Implementation//SpecificComponents/SUV/config/TEST:4670-4976
    /tags/QR_20131111/Implementation/SpecificComponents/SUV/config/TEST:4669
    /tags/QR_20131211/Implementation/SpecificComponents/SUV/config/TEST:5138
    /trunk/Implementation/SpecificComponents/SUV/config/OBC:4669-4949
    /trunk/Implementation/SpecificComponents/SUV/config/TEST:5137-5273
    PROPS-END
    

    【讨论】:

    • 哇,反应真快!但是你能解释一下 sed 的语法吗?我总是用 N 找到多行解决方案。
    • @CSchulz 正如上面编辑中提到的,该命令在匹配两个模式的行之间执行替换。我想你可以计算出反向引用部分。
    • 是的,反向引用部分对我来说很清楚,我只是想知道替换如何忽略 V 498。带逗号的部分是gnu特殊地址格式吧?
    • @CSchulz V 498忽略,因为它与替换命令中的模式不匹配。
    • +1,但脚本可以更短,\4部分没用:sed -r '/svn:mergeinfo/,/PROPS-END/{s#(/code)(/(branches|tags|trunk))#\2#}' file
    【解决方案2】:
    perl -pe '$/ ="PROPS-END"; s!/code(?=/(?:branches|tags|trunk))!!g' file
    

    输出

    K 13
    svn:mergeinfo
    V 498
    /branches/TEST_ENVIRONMENT_OBC/Implementation//SpecificComponents/SUV/config/TEST:4670-4976
    /tags/QR_20131111/Implementation/SpecificComponents/SUV/config/TEST:4669
    /tags/QR_20131211/Implementation/SpecificComponents/SUV/config/TEST:5138
    /trunk/Implementation/SpecificComponents/SUV/config/OBC:4669-4949
    /trunk/Implementation/SpecificComponents/SUV/config/TEST:5137-5273
    PROPS-END
    

    【讨论】:

      【解决方案3】:

      使用 awk

      awk '/svn:mergeinfo/,/PROPS-END/{sub(/^\/code/,"")}1' file
      

      【讨论】:

        【解决方案4】:

        您还需要添加全局标志。多行只替换一次然后完成,尽管目标跨越多行。全局标志使它继续尝试匹配,直到没有更多的输入文本。

        只需在正则表达式末尾的m 之后添加g

        【讨论】:

        • 感谢您的快速答复。 g 标志不会改变任何东西。但这意味着我必须多次运行替换,直到每一行都被更改?
        猜你喜欢
        • 2021-10-19
        • 1970-01-01
        • 1970-01-01
        • 2022-11-28
        • 2013-10-18
        • 2016-10-13
        • 2021-01-31
        • 1970-01-01
        相关资源
        最近更新 更多