Sed: add after last appearance

Let's say I have the following 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>
</preferences>

      

My task is to add text immediately after the last occurrence </section>

.

Looking at these two, it seems like using tac

would be easier, but I don't understand how to do it: Using sed to append a line to the fourth occurrence of a pattern , http://www.unix.com/unix-dummies-questions-answers/ 46294-add-line-after-last-occurnace-pattern.html # post302149709

Thank.

+4


source to share


7 replies


It's easier to add things before the first occurrence of the line:

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

      

Results:



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

      

You can read more about how to insert a line before a line here . NTN.

+2


source


This might work for you (GNU sed):

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

      



In essence: when you encounter a line containing /section

, start storing all remaining lines at the end of the file in holding space (HS). If lines are already on hold and another such line is encountered, print lines in HS and start saving lines again. At the end of the file, insert the line you want and print the saved lines.

+5


source


Insert text after the last section tag, i.e. before the end of the "preferences" tag:

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

      

The result looks like this:

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

      

To do it locally, use the flag -i

:

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

      

Make it like a channel:

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

      

The host system using sed

, and regular expressions in XML tend to lead to problems because XML is not regex-based or string-based. To do it better, use a real XML parser in perl, python, ruby, java, etc.

+2


source


One of the methods:

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

      

This snippet adds a new one <section>

to the file 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>

      

+2


source


with awk you can do this

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

      

Output

Hello
</preferences>

      

+1


source


@Steve's answer above is the correct way to do it, but it contains a quirk that crashes on OS X. The correct, portable way to encode multi-line inserts is sed

for:

  • Precede the actual content with a new line,
  • Escape every new line (including the first one after the command) with a backslash.

Here's an updated example given the text in your opening post:

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

      


For reference, excerpts from 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

      

... and from the 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

      

+1


source


here is my method when i am going to add a line after the last one #include

.

grep -n '#include' $file | tail -1 | cut -f1 -d: | xargs -I % echo %+1 | bc | 
xargs -I '{}' sed -i '{}i// clang-format off' $file

      

  • Get the line number of the last occurrence and add 1 to it.
  • Use sed to insert a line into a line.
0


source







All Articles