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>