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.
source to share
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.
source to share
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.
source to share
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.
source to share
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>
source to share
@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
source to share
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.
source to share