Home > Software design >  Add String to New Line After Final Pattern Match
Add String to New Line After Final Pattern Match

Time:05-24

I am trying to add the follow string after the last pattern match in a text file.

Text File

<MultiGeometry>
<Polygon>1
</Polygon>
<Polygon>2
</Polygon>
<Polygon>3
</Polygon>
<Polygon>4
</Polygon>
<Polygon>5
</Polygon>

Attempted Code

sed -i '/<\/Polygon>/a</\MultiGeometry>' text_file

This code inserts </MultiGeometry> after each match of </Polygon> instead of the last match of </Polygon> in the text file.

Current Result

<MultiGeometry>
<Polygon>1
</Polygon>
</MultiGeometry>
<Polygon>2
</Polygon>
</MultiGeometry>
<Polygon>3
</Polygon>
</MultiGeometry>
<Polygon>4
</Polygon>
</MultiGeometry>
<Polygon>5
</Polygon>
</MultiGeometry>

Expected Result

<MultiGeometry>
<Polygon>1
</Polygon>
<Polygon>2
</Polygon>
<Polygon>3
</Polygon>
<Polygon>4
</Polygon>
<Polygon>5
</Polygon>
</MultiGeometry>

CodePudding user response:

A Perl solution:

tac text_file | perl -lpe 'next LINE if $seen; s{</Polygon>}{$&</MultiGeometry>} and $seen  ;' > temp
mv temp text_file

tac : print lines in reverse order, from last to first.

The Perl one-liner uses these command line flags:
-e : Tells Perl to look for code in-line, instead of in a file.
-n : Loop over the input one line at a time, assigning it to $_ by default.
-p : Loop over the input one line at a time, assigning it to $_ by default. Add print $_ after each loop iteration.
-l : Strip the input line separator ("\n" on *NIX by default) before executing the code in-line, and append it when printing.

$& : matched pattern, here </Polygon>.
$seen : undef (false) if we have not replaced yet, and 1 (true) if we have. Enables doing 1 and only 1 replacement of the pattern, the first one from the end = the last one in the original file.

CodePudding user response:

Using sed but indicating $ (last line in file or in LHS result) as an address

sed -irn '/<[/]Polygon>/ { $ s@</Polygon>@&</MultiGeometry>@ }' list1.txt

sed expression parts

/<[/]Polygon>/ get all lines matching pattern
{ $ s@</Polygon>@&</MultiGeometry>@ } make the replacement only on last line of matched ones. $ means last line, & refers to the whole LHS pattern.

Note: @ is used instead of / in s/ / / sed expression for better readability since forward slashes do not require escaping.

CodePudding user response:

Using gnu-sed you can use -z flag and match .*</Polygon> to make sure to match last </Polygon> because .* is greedy to match longest match before matching </Polygon>.

sed -z 's~.*</Polygon>~&\n</MultiGeometry>~' file

<MultiGeometry>
<Polygon>1
</Polygon>
<Polygon>2
</Polygon>
<Polygon>3
</Polygon>
<Polygon>4
</Polygon>
<Polygon>5
</Polygon>
</MultiGeometry>
  • Related