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>
