Sed:在最后一次出现后追加

时间:2013-02-11 00:06:56

标签: sed

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

<?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>

我的任务是在最后一次出现</section>后立即添加文字。

看看这两个似乎使用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

感谢。

7 个答案:

答案 0 :(得分:5)

这可能适合你(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中的线并再次开始存储线。在文件的末尾插入所需的字符串并打印出存储的行。

答案 1 :(得分:2)

要在最后一个标记之后插入文字,即在结束“首选项”标记之前插入文字:

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&#'

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

答案 2 :(得分:2)

一种方式:

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

此代码段在<section>文件中添加了新的XML

RESULT

<?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>

答案 3 :(得分: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。

答案 4 :(得分:1)

用awk你可以这样做

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

输出

Hello
</preferences>

答案 5 :(得分:1)

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

  1. 使用换行符添加实际内容
  2. 使用反斜杠转义每个换行符(包括命令后的第一个换行符)。
  3. 这是一个更新的示例,给出了初始帖子中的文字:

    sed

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

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

    ...来自GNU 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
    

答案 6 :(得分:0)

这是我要在最后一个#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在该行插入一行。