【问题标题】:Replace specific string, and copy the text block below it替换特定字符串,并复制其下方的文本块
【发布时间】:2015-02-05 21:42:41
【问题描述】:

我有以下两个文本文件

a.txt:

Hello, my name is <name>
and I like flowers.

b.txt:

Susan
Katie
Caitlynn

我想对其进行操作以在 c.txt 中具有以下输出:

Hello, my name is Susan
and I like flowers.

Hello, my name is Katie
and I like flowers.

Hello, my name is Caitlynn
and I like flowers.

等等等等。

我可以在一个实例中替换它们,但不知道如何连续读取 b.txt 以继续替换

【问题讨论】:

    标签: linux bash sed grep


    【解决方案1】:

    第一版问题的解决方案

    这是sed 解决方案:

    $ sed -r '1{h;d}; G; s/(.*)\n(.*)<name>(.*)/\2\1\3/' a.txt b.txt
    Hello, my name is Susan
    Hello, my name is Katie
    Hello, my name is Caitlynn
    

    工作原理

    • 1{h;d}

      sed 看到的第一行来自a.txt。这会将该行保存在保持空间中,然后跳过以重新开始下一行。

    • G

      第二行和所有后续行来自b.txt。对于每个这样的行,此命令将保留空间附加到该行。执行后,模式空间的名称(来自b.txt)后跟一个换行符,然后是来自a.txt 的行。

    • s/(.*)\n(.*)&lt;name&gt;(.*)/\2\1\3/

      这会重新排列模式空间,将名称放在应有的位置。

    第二版问题的解决方案

    $ sed -r '1{h;d}; 2{H;d}; G; s/(.*)\n(.*)<name>(.*)/\2\1\3/' a2.txt b.txt
    Hello, my name is Susan
    and I like flowers.
    Hello, my name is Katie
    and I like flowers.
    Hello, my name is Caitlynn
    and I like flowers.
    

    【讨论】:

      【解决方案2】:

      你可以使用awk:

      awk 'FNR==NR{a[$1]++; next} 
           {for (i in a) { s=$0; sub(/<name>/, i, s); print s}}' b.txt a.txt
      Hello, my name is Caitlynn
      Hello, my name is Susan
      Hello, my name is Katie
      

      更新:基于已编辑的问题:

      awk 'FNR==NR{a[$1]++; next} /<name>/{curLine=$0; getline nextLine;
        for (i in a) {s=curLine; sub(/<name>/, i, s); print s; print nextLine}}' b.txt a.txt
      Hello, my name is Caitlynn
      and I like flowers.
      Hello, my name is Susan
      and I like flowers.
      Hello, my name is Katie
      and I like flowers.
      

      【讨论】:

      • 这可能会:awk 'FNR==NR{a[$1]++; next} {for (i in a) {$NF=i;print}}'
      • 谢谢,是的,如果&lt;name&gt; 始终是最后一个字段,那肯定会起作用
      • @anubhava,当我运行你的awk 命令时,它会以相反的顺序打印名称。知道为什么吗?
      • 这不是逆序,它只是没有顺序,因为关联顺序不维护 awk 中的插入顺序。如果 OP 想要原始订单,我可以为此添加修复程序。
      【解决方案3】:

      你也可以试试 sed + bash 循环:

      for x in $(cat b.txt); do sed -e "s/<name>/$x/" a.txt; done
      

      如果你需要在句子之间加行

      for x in $(cat b.txt); do sed -e "s/<name>/$x/" a.txt; echo ""; done
      

      【讨论】:

        【解决方案4】:
        $ awk 'NR==FNR{tmplt=tmplt $0 ORS; next} {block=tmplt; sub(/<name>/,$0,block); print block}' a.txt b.txt
        Hello, my name is Susan
        and I like flowers.
        
        Hello, my name is Katie
        and I like flowers.
        
        Hello, my name is Caitlynn
        and I like flowers.
        

        【讨论】:

          【解决方案5】:

          战术性地使用 sed 及其 e command 如下

           sed 's#.*#sed "s/\\(.*\\)<name>\\(.*\\)/\\n\\1&\\2/" a.txt #e' b.txt > c.txt
          

          c.txt 是您的新文件,具有预期结果

          结果

          Hello, my name is Susan
          and I like flowers.
          
          Hello, my name is Katie
          and I like flowers.
          
          Hello, my name is Caitlynn
          and I like flowers.
          

          【讨论】:

            猜你喜欢
            • 2012-07-20
            • 2022-08-07
            • 2020-12-15
            • 1970-01-01
            • 2014-06-21
            • 2021-12-14
            • 2017-03-02
            • 1970-01-01
            • 2023-03-25
            相关资源
            最近更新 更多