Linux bash脚本 - 替换文件中最后一次出现的字符串

时间:2022-03-05 22:05:01

I have a XML file that looks something like this, and I only want to replace the last occurrence of /Shipment with /ShipHdr /ShipmentX:

我有一个看起来像这样的XML文件,我只想用/ ShipHdr / ShipmentX替换/ Shipment的最后一次出现:

<ShipmentX>
  <ShipHdr>
   <RefID>REF01</RefID>
   <HeaderReferenceNumber>1234565</HeaderReferenceNumber>
   <Shipment>
     <RefCode>GHIJK</RefCode>
     <ShipmentStatusCode>FG</ShipmentStatusCode>
   </Shipment>
   <Summary>
     <TotalWeight>10</TotalWeight>
   </Summary>
</Shipment>

Output:

输出:

<ShipmentX>
  <ShipHdr>
   <RefID>REF01</RefID>
   <HeaderReferenceNumber>1234565</HeaderReferenceNumber>
   <Shipment>
     <RefCode>GHIJK</RefCode>
     <ShipmentStatusCode>FG</ShipmentStatusCode>
   </Shipment>
   <Summary>
     <TotalWeight>10</TotalWeight>
   </Summary>
  </ShipHdr>
</ShipmentX>

Any advice on how I can do this using perl or sed in a bash script?

关于如何使用perl或sed在bash脚本中执行此操作的任何建议?

Thanks!

谢谢!

2 个解决方案

#1


1  

Using tac and awk:

使用tac和awk:

tac xml | awk '!p && /<\/Shipment>/{p=1;print "</ShipmentX>\n   </ShipHdr>"; next} 1'| tac
<ShipmentX>
  <ShipHdr>
   <RefID>REF01</RefID>
   <HeaderReferenceNumber>1234565</HeaderReferenceNumber>
   <Shipment>
     <RefCode>GHIJK</RefCode>
     <ShipmentStatusCode>FG</ShipmentStatusCode>
   </Shipment>
   <Summary>
     <TotalWeight>10</TotalWeight>
   </Summary>
   </ShipHdr>
</ShipmentX>

#2


0  

In Perl the regex is $n =~ s/(?s).*\K<\/Shipment>/<\/ShipHdr> <\/ShipmentX>/;

在Perl中,正则表达式是$ n = ~s /(?s)。* \ K <\ / Shipment> / <\ / ShipHdr> <\ / ShipmentX> /;

Or, you can avoid the LTS with this syntax:

或者,您可以使用以下语法避免使用LTS:

$n =~ s{(?s).*\K</Shipment>}{</ShipHdr> </ShipmentX>};

$ n = ~s {(?s)。* \ K } { };

This regex finds only the last occurance of </Shipment>, no matter what comes after it, ie. there won't be another </Shipment> after it.

这个正则表达式只找到 的最后一次出现,无论后面是什么,即。它之后不会有另一个 。

#1


1  

Using tac and awk:

使用tac和awk:

tac xml | awk '!p && /<\/Shipment>/{p=1;print "</ShipmentX>\n   </ShipHdr>"; next} 1'| tac
<ShipmentX>
  <ShipHdr>
   <RefID>REF01</RefID>
   <HeaderReferenceNumber>1234565</HeaderReferenceNumber>
   <Shipment>
     <RefCode>GHIJK</RefCode>
     <ShipmentStatusCode>FG</ShipmentStatusCode>
   </Shipment>
   <Summary>
     <TotalWeight>10</TotalWeight>
   </Summary>
   </ShipHdr>
</ShipmentX>

#2


0  

In Perl the regex is $n =~ s/(?s).*\K<\/Shipment>/<\/ShipHdr> <\/ShipmentX>/;

在Perl中,正则表达式是$ n = ~s /(?s)。* \ K <\ / Shipment> / <\ / ShipHdr> <\ / ShipmentX> /;

Or, you can avoid the LTS with this syntax:

或者,您可以使用以下语法避免使用LTS:

$n =~ s{(?s).*\K</Shipment>}{</ShipHdr> </ShipmentX>};

$ n = ~s {(?s)。* \ K } { };

This regex finds only the last occurance of </Shipment>, no matter what comes after it, ie. there won't be another </Shipment> after it.

这个正则表达式只找到 的最后一次出现,无论后面是什么,即。它之后不会有另一个 。