【问题标题】:modifying a text file with regex使用正则表达式修改文本文件
【发布时间】:2013-04-30 23:21:59
【问题描述】:

我有一个包含特定字符串的源文件,并且想用另一个文件的内容替换该字符串的第一个(在这种情况下,唯一的)实例。类似的东西:

> cat source.txt
Hello
KEYWORD
Hi
> cat replacement.txt
Replacement
> <sed command>
> cat source.txt
Hello
Replacement
Hi

有没有办法用 sed 做到这一点?还是其他编辑器?

【问题讨论】:

    标签: linux file shell sed replace


    【解决方案1】:

    我认为 awk 可以更轻松地完成这项工作:

    如果你想在replace.txt中保留结束的换行符

    awk -v RS="\0" -v ORS="" 'NR==FNR{r=$0;next}{sub(/KEYWORD/,r)}1' replace.txt source.txt
    

    如果您想从 replace.txt 中删除结尾 \n

    awk -v RS="\0" -v ORS="" 'NR==FNR{r=$0;sub(/\n$/,"",r);next}{sub(/KEYWORD/,r)}1'  replace.txt source.txt
    

    无论您的 replace.txt 是单行还是多行,上述行都有效。

    例如:

    kent$  head file1 file2                                                         
    ==> file1 <==
    Hello
    KEYWORD
    Hi
    KEYWORD
    
    ==> file2 <==
    rep_line1
    rep_line2
    
    kent$  awk -v RS="\0" -v ORS="" 'NR==FNR{r=$0;next}{sub(/KEYWORD\n/,r)}1' file2 file1
    Hello
    rep_line1
    rep_line2
    Hi
    KEYWORD
    

    你可以看到,只有file1中的第一个KEYWORD被替换了。但是 awk 无法将更改写回输入文件。我们能做的是:

    awk '...' replace.txt src.txt > /tmp/t.txt && mv /tmp/t.txt /path/to/src.txt
    

    用 gawk 测试了 awk 单行。不保证它适用于所有 awk 实现。如果你有一个非 gnu awk,你应该测试它。

    感谢Ed Morton的建议。

    【讨论】:

    • 这对我不起作用-该命令仅从替换文件中输出文本,而不保留任何源文件。我的替换文本是多行的,并且有大量特殊字符 - 这会导致问题吗?
    • 多行,特殊字符应该没有问题。我回答的最后一行给出了将更改写回 src.txt 的方式。我希望你阅读它。
    • +1 但您应该提到此解决方案仅限 gawk。它可以与其他一些 awk 一起使用,但不能保证设置 RS='\0' 会将整个文件作为单个记录读取。
    • 另外,解决方案依赖于仅出现在文件末尾的后续 KEYWORD,我认为这与 OPs 输入不匹配 - 最好在第一个 sub( ) 并且仅在未设置该标志时执行 sub() ,例如!f{sub(/KEYWORD/,r);f=1}
    • @EdMorton 我认为您的意思是“在一行的末尾”。我认为我们不需要那个标志,因为 file1 在一个记录中,(RS="\0") 对吗?我认为 KEYWORD 是一种线条图案。因此在末尾添加了\n
    【解决方案2】:

    快速简便的方法:

    sed s/KEYWORD/`cat replacement.txt`/ source.txt > output.txt
    

    【讨论】:

    • 替换文件中包含 sed 存在问题的特殊字符 - 我收到未终止 s 命令的错误。有什么解决办法吗?
    • 您可以将正斜杠替换为不同的符号,例如 |,理想情况下您不会将其用作替代符号。或者,您可以尝试转义字符串,但在我回到计算机之前我无法提供示例。 (我在打电话)
    • 你不能可靠地使用上面的方法,不要浪费你的时间去剥洋葱,解决它会出现的问题。只需使用@kent 的 awk 解决方案。
    【解决方案3】:
    $ cat source.txt
    Hello
    KEYWORD
    
    Hi
    
    
    
    KEYWORD
    
    KEYWORD
    
    $ cat replacement.txt 
    Replacement
    multiline?
    $ sed -ir  "0,/KEYWORD/s//$(cat replacement.txt | sed 's/$/^M/'|tr -d '\n' ) )/" source.txt 
    $ cat source.txt
    Hello
    Replacement
    multiline?
    Hi
    
    
    
    KEYWORD
    
    KEYWORD
    
    $
    

    【讨论】:

    • 我想出了和你一样的。但这将在 source.txt 中用KEYWORD 替换 all 行,这不是 OP 必需的。 sed 可以实现仅替换第一个出现的行,但是您必须对 src.txt 进行一些更改然后返回(例如,将 \n 替换为其他字符)或在替换发生后在保留空间中进行标记。并检查所有以后传入的行的标记。所以我去了awk。
    • 公平评论。查看修改后的版本
    • 为什么是猫?为什么要在输出中插入 control-Ms?当replacement.txt 包含“/”时它会做什么?只需使用@kent 的 awk 解决方案。
    • 我没有使用猫。示例中的 Cat 仅显示应用 sed 之前和之后的文件内容。
    猜你喜欢
    • 1970-01-01
    • 2014-01-16
    • 1970-01-01
    • 1970-01-01
    • 2019-02-02
    • 1970-01-01
    • 2015-04-26
    相关资源
    最近更新 更多