【问题标题】:sed find regex pattern then find next regex pattern (variable multi line) and replacesed 找到正则表达式模式然后找到下一个正则表达式模式(变量多行)并替换
【发布时间】:2021-07-23 19:13:19
【问题描述】:

我正在尝试找到一种使用 sed 将字符串“.sh”插入到文本文件中特定行的方法。我遇到的问题是,如果以前的正则表达式匹配,我只想插入字符串,它还必须支持“名称”和“扩展”标签之间的可变行数并且是幂等的,所以我可以多次运行它只为“extension”标记的空格分隔列表插入一次“.sh”。

这是文本文件的小sn-p:-

    <name>gba</name>
    <fullname>Game Boy Advance</fullname>
    <manufacturer>Nintendo</manufacturer>
    <release>2001</release>
    <hardware>portable</hardware>
    <path>/storage/roms/gba</path>
    <extension>.gba .GBA .zip .ZIP .7z .7Z</extension>

所以我想将 &lt;extension&gt;.gba .GBA .zip .ZIP .7z .7Z&lt;/extension&gt; 更改为 &lt;extension&gt;.gba .GBA .zip .ZIP .7z .7Z .sh&lt;/extension&gt; 仅当名称标签为 &lt;name&gt;gba&lt;/name&gt;

这是迄今为止我想出的最好的,但它有两个问题,首先,代码的后续执行重复插入,其次它的行数固定(6),可能并非总是如此:-

sed -i '/&lt;name&gt;gba&lt;\/name&gt;/{n;n;n;n;n;n;s/&lt;\/extension&gt;/ .sh&lt;\/extension&gt;/}' /tmp/test.txt

【问题讨论】:

    标签: awk sed


    【解决方案1】:

    使用GNU sed 测试(其他实现的语法可能有所不同):

    sed '/<name>gba</,/<extension>/{/<extension>/{/\.sh/! s/<\/extension>/ .sh&/}}'
    
    • /&lt;name&gt;gba&lt;/,/&lt;extension&gt;/ 这将匹配以包含 &lt;name&gt;gba&lt; 的行开始并以包含 &lt;extension&gt; 的行结束的行范围
      • 这是基于给定的样本,如果您需要更稳健的匹配条件,您可以修改正则表达式
    • {} 有助于对仅针对给定匹配条件执行的命令进行分组
    • 对于这样的行范围:
      • /&lt;extension&gt;/ 只匹配这一行
      • /\.sh/! 检查它是否没有.sh
      • s/&lt;\/extension&gt;/ .sh&amp;/ 为此类行添加 .sh

    【讨论】:

      【解决方案2】:

      如果您对awk 没问题,请尝试关注。使用所示示例编写和测试。

      awk '
      /<name>/{ found="" }
      /<name>gba<\/name>/{
        found=1
      }
      found && /<extension>/ && !/\.sh</{
        sub(/<\//," .sh&")
        found=""
      }
      1
      '  Input_file
      

      说明:为上述添加详细说明。

      awk '                     ##Starting awk program from here.
      /<name>/{ found="" }
      /<name>gba<\/name>/{      ##Searching string <name>gba</name>
        found=1                 ##Setting found to 1 here.
      }
      found && /<extension>/ && !/\.sh</{   ##Checking found is set and <extension> is found in line then do following.
        sub(/<\//," .sh&")      ##Substituting </ with space .sh and matched value in current line.
        found=""                ##Nullifying found here.
      }
      1                         ##Printing current line here.
      '  Input_file             ##Mentioning Input_file here.
      

      【讨论】:

      • 谢谢!,我对 awk 很好,如果我执行上面的代码并将其写入与输入文件相同的名称(使用 /tmp/test.txt &gt; tmp &amp;&amp; mv tmp /tmp/test.txt)然后重新运行,我会看到重复在扩展标记列表中插入“.sh”,因此它似乎不是幂等的。
      • @binhex,当然,我已经添加了 1 个条件,它只会在 .sh 不存在时进行替换,请检查一次,让我知道它是怎么回事,干杯。
      • 感谢 RavinderSingh13 您的修订工作!,我想我将不得不向@Sundeep 提供他唯一的 sed 解决方案接受的答案,但我非常感谢您的回复和代码故障。
      【解决方案3】:

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

      sed '/<name>gba<\/name>/{:a;n;/<\/extension>/!ba;/\.sh/!s/<\/extension/ .sh&/}' file
      

      关注包含&lt;name&gt;gba&lt;/name&gt;的行。

      打印当前行,获取下一行,如果该行不包含&lt;/extension&gt;,则重复。

      否则,如果当前行不包含.sh,则将其添加到上述字符串之前。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多