【问题标题】:Sed: append after last occurrenceSed:在最后一次出现后追加
【发布时间】:2021-07-01 09:04:36
【问题描述】:

假设我有以下类型的文件:

<?xml version="1.0" encoding="utf-8"?>
<preferences>
  <section id="widgets">
    <value id="version" xml:space="preserve">1</value>
  </section>
  <section id="wuid-b2a8e6b8-6619-714e-9cfe-466c27c90902">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/opera-adblock-1.3.4-1.oex</value>
  </section>
  <section id="wuid-0c5cfdb2-8e51-f149-a1e7-51d66240ed7a">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/flag-button-1.5.4-1.oex</value>
  </section>
</preferences>

我的任务是在最后一次出现 &lt;/section&gt; 之后添加文本。

看看这两个,似乎使用tac 会更简单,但我也不明白该怎么做:Using sed to append a string to the fourth occurrence of a patternhttp://www.unix.com/unix-dummies-questions-answers/46294-add-line-after-last-occurnace-pattern.html#post302149709

谢谢。

【问题讨论】:

  • 为什么不在&lt;/preferences&gt;第一次出现之前添加呢?
  • @Blender,嗯,因为我很愚蠢。那我该怎么做呢?

标签: sed


【解决方案1】:

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

sed '/\/section/{x;/./p;x;h;d};x;/./!{x;b};x;H;$!d;x;s/\/section[^\n]*\n/&  HELLO\n/' file

本质上:遇到包含/section 的行时,开始将所有剩余行存储到文件末尾的保持空间(HS)中。如果行已经在保持空间中并且遇到另一个这样的行,则打印 HS 中的行并再次开始存储行。在文件末尾插入所需的字符串并打印出存储的行。

【讨论】:

  • 谢谢。其他人都在解决 OP 的问题,这当然对他们以及网站的大部分内容都非常有用。您是唯一回答所提问题的人(并且您仍然发布了一个有助于 OP 的解决方案),这有助于像我这样来自 Google 并有类似问题的人。
【解决方案2】:

在第一次出现字符串之前添加东西更容易:

sed '/<\/preferences>/i\ADD SOME TEXT\nADD SOME MORE TEXT' file

结果:

<?xml version="1.0" encoding="utf-8"?>
<preferences>
  <section id="widgets">
    <value id="version" xml:space="preserve">1</value>
  </section>
  <section id="wuid-b2a8e6b8-6619-714e-9cfe-466c27c90902">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/opera-adblock-1.3.4-1.oex</value>
  </section>
  <section id="wuid-0c5cfdb2-8e51-f149-a1e7-51d66240ed7a">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/flag-button-1.5.4-1.oex</value>
  </section>
    ADD SOME TEXT
    ADD SOME MORE TEXT
</preferences>

您可以阅读有关如何在字符串 here 之前插入一行的更多信息。 HTH。

【讨论】:

  • 这是不正确的。新文本必须换行。
  • @ELLIOTTCABLE:确实如此。你真的效仿了吗?
  • 是的。 sed: 1: "/&lt;\/preferences&gt;/i\ADD ...": extra characters after \ at the end of i command
  • 啊哈哈。事实证明,gnu sed 对这条规则的了解不如 Mac OS X 上的 sed。也就是说,在 gnu sed 的两个手册页中这样描述的>和 OS X sed;将内容放在新行上既是官方要求,也更便于携带。
【解决方案3】:

一种方式:

sed -i 's@</preferences>@  <section id="x">\n   <value id="path to widget data" xml:space="preserve">{Preferences}widgets/xxxx</value>\n  </section>\n&@' file.xml

这个 sn-p 在XML 文件中添加一个新的&lt;section&gt;

结果

<?xml version="1.0" encoding="utf-8"?>
<preferences>
  <section id="widgets">
    <value id="version" xml:space="preserve">1</value>
  </section>
  <section id="wuid-b2a8e6b8-6619-714e-9cfe-466c27c90902">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/opera-adblock-1.3.4-1.oex</value>
  </section>
  <section id="wuid-0c5cfdb2-8e51-f149-a1e7-51d66240ed7a">
    <value id="path to widget data" xml:space="preserve">{Preferences}widgets/flag-button-1.5.4-1.oex</value>
  </section>
  <section id="x">
   <value id="path to widget data" xml:space="preserve">{Preferences}widgets/xxxx</value>
  </section>
</preferences>

【讨论】:

  • 与其写&lt;/preferences&gt; 两次,不如像joelparkerhenderson 那样将模式分组或使用&amp; 符号?它会让你的眼睛更容易阅读你的单眼线。
【解决方案4】:

在最后一个section标签之后插入文本,即在结束“preferences”标签之前:

sed 's#</preferences>#  HELLO\n&#' file.xml

输出如下:

...
  </section>
  HELLO
</preferences>

要做到这一点,请使用-i 标志:

sed -i 's#</preferences>#  HELLO\n&#' file.xml

将其作为管道:

cat file.xml | ...whatever... | sed 's#</preferences>#  HELLO\n&#'

请注意,在 XML 上使用 sed 和正则表达式往往会导致问题,因为 XML 既不是基于正则表达式也不是基于行。要做得更好,请在 perl、python、ruby、java 等中使用真正的 XML 解析器。

【讨论】:

  • cat file.xml | sedcat的无用用法:sed可以直接读取file.xml
  • @sputnick 好点;我会在我的回答中澄清这一点。谢谢!
【解决方案5】:

使用 awk 你可以这样做

awk '$0 ~ /<\/pref/{print "Hello\n"$0}' temp.txt

输出

Hello
</preferences>

【讨论】:

    【解决方案6】:

    @Steve 上面的答案是解决此问题的正确方法,但它包含一个导致它在 OS X 上失败的怪癖。编码多行插入 sed 脚本的正确、可移植的方法是:

    1. 在实际内容之前加上换行符,
    2. 使用反斜杠转义每个换行符(包括命令后的第一个换行符)。

    根据您最初帖子中的文字,这是一个更新的示例:

    sed -i '' '/<\/preferences>/i\
    ADD SOME TEXT\
    ADD SOME MORE TEXT\
    ' test.xml
    

    供参考,摘自the OS X sed(1) manpage

         [2addr]H
                 Append a newline character followed by the contents of the pattern space to the hold space.
    
         [1addr]i\
         text    Write text to the standard output.
    
         [2addr]l
                 (The letter ell.)  Write the pattern space to the standard output in a visually unambiguous
    

    … 来自GNU sed(1) manpage:

           text   Append text, which has each embedded newline preceded by a back-
              slash.
    
           i \
    
           text   Insert text, which has each embedded newline preceded by a back-
              slash.
    
           q      Immediately  quit  the  sed  script  without processing any more
              input, except that if auto-print is  not  disabled  the  current
    

    【讨论】:

      【解决方案7】:

      这是我要在最后一个#include 之后添加一行时的方法。

      grep -n '#include' $file | tail -1 | cut -f1 -d: | xargs -I % echo %+1 | bc | 
      xargs -I '{}' sed -i '{}i// clang-format off' $file
      
      • 获取最后出现的行号并将其加 1。
      • 使用 sed 在该行插入一行。

      【讨论】:

        猜你喜欢
        • 2017-07-11
        • 2013-09-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多