Sed 只替换一次而不是多次

Sed substitutes just once instead of multiple times

我有一个包含大量以下代码的 XML 文件:

<BankAccount code="NL18INGB0001234567">
<BankAccountType code="NL">
<Description/>

我需要将 code="NL" 替换为 code="IBA",但前提是 BankAccount 中包含 INGB000。我使用以下 sed 命令:

sed 'N;s/\(INGB000[0-9].*NL\)/_OUD/g;s/NL_OUD/IBA/g' file1.xml > file2.xml

问题是这个命令只替换第一个而不是所有其他的。

我希望 -g 选项可以进行全局匹配,但这没有用。

我也试过:

sed ':a;N;ta;s/\(INGB000[0-9].*NL\)/_OUD/g;s/NL_OUD/IBA/g' file1.xml > file2.xml

我做错了什么?

输入:

<?xml version='1.0' encoding='UTF-8' ?>
<eExact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="eExact-Schema.xsd">
    <Accounts>
        <Account code="1206" status="A" type="C">
            <Name>John Doe</Name>
            <Contacts>
                <Contact default="1" gender="M" status="A">
                    <LastName>Client: 10000</LastName>
                    <Initials/>
                    <Addresses>
                        <Address type="V">
                            <AddressLine1>one-way-street</AddressLine1>
                            <PostalCode>1000 AB</PostalCode>
                            <City>Simcity 1</City>
                            <Country code="NL"/>
                        </Address>
                    </Addresses>
                </Contact>
            </Contacts>
            <Debtor code="1206" number="1206">
                <BankAccounts>
                    <BankAccount code="NL93INGB0001234567">
                        <BankAccountType code="NL">
                            <Description/>
                        </BankAccountType>
                        <Bank code="">
                            <Name/>
                            <IBAN>NL93INGB0001234567</IBAN>
                        </Bank>
                        <SDDMandate>
                            <MndtId>02001234-0000004</MndtId>
                            <DtOfSgntr>2000-11-01</DtOfSgntr>
                            <LclInstrm>Core</LclInstrm>
                            <LastSDDDt/>
                        </SDDMandate>
                    </BankAccount>
                </BankAccounts>
                <SendReminder>1</SendReminder>
            </Debtor>
        </Account>

        <Account code="1123" status="A" type="C">
            <Name>Johny Doe</Name>
            <Contacts>
                <Contact default="1" gender="V" status="A">
                    <LastName>Client: 10001</LastName>
                    <Addresses>
                        <Address type="V">
                            <AddressLine1>one-way-street</AddressLine1>
                            <PostalCode>1000 AB</PostalCode>
                            <City>Simcity 2</City>
                            <Country code="NL"/>
                        </Address>
                    </Addresses>
                </Contact>
            </Contacts>
            <Debtor code="1123" number="1123">
                <BankAccounts>
                    <BankAccount code="NL25RABO0123456789">
                        <BankAccountType code="NL">
                            <Description/>
                        </BankAccountType>
                        <Bank code="">
                            <Name/>
                            <IBAN>NL25RABO0123456789</IBAN>
                        </Bank>
                        <SDDMandate>
                            <MndtId>02001234-0000003</MndtId>
                            <DtOfSgntr>2000-02-03</DtOfSgntr>
                            <LclInstrm>Core</LclInstrm>
                            <LastSDDDt/>
                        </SDDMandate>
                    </BankAccount>
                </BankAccounts>
                <SendReminder>1</SendReminder>
            </Debtor>
        </Account>
        <Account code="1109" status="A" type="C">
            <Name>Joan Doe</Name>
            <Contacts>
                <Contact default="1" gender="V" status="A">
                    <LastName>Client: 10002</LastName>
                    <Initials/>
                    <Addresses>
                        <Address type="V">
                            <AddressLine1>one-way-street</AddressLine1>
                            <PostalCode>1000 AB</PostalCode>
                            <City>Simcity 1</City>
                            <Country code="NL"/>
                        </Address>
                    </Addresses>
                </Contact>
            </Contacts>
            <Debtor code="1109" number="1109">
                <BankAccounts>
                    <BankAccount code="NL46RABO0123456789">
                        <BankAccountType code="NL">
                            <Description/>
                        </BankAccountType>
                        <Bank code="">
                            <Name/>
                            <IBAN>NL46RABO0123456789</IBAN>
                        </Bank>
                        <SDDMandate>
                            <MndtId>02001234-0000002</MndtId>
                            <DtOfSgntr>2000-11-01</DtOfSgntr>
                            <LclInstrm>Core</LclInstrm>
                            <LastSDDDt/>
                        </SDDMandate>
                    </BankAccount>
                </BankAccounts>
                <SendReminder>1</SendReminder>
            </Debtor>
        </Account>
        <Account code="1631" status="A" type="C">
            <Name>Flint</Name>
            <Contacts>
                <Contact default="1" gender="V" status="A">
                    <LastName>Client: 10003</LastName>
                    <Initials/>
                    <Addresses>
                        <Address type="V">
                            <AddressLine1>one-way-street</AddressLine1>
                            <PostalCode>1000 AB</PostalCode>
                            <City>Simcity 3</City>
                            <Country code="NL"/>
                        </Address>
                    </Addresses>
                </Contact>
            </Contacts>
            <Debtor code="1631" number="1631">
                <BankAccounts>
                    <BankAccount code="NL10INGB0001234567">
                        <BankAccountType code="NL">
                            <Description/>
                        </BankAccountType>
                        <Bank code="">
                            <Name/>
                            <IBAN>NL10INGB0001234567</IBAN>
                        </Bank>
                        <SDDMandate>
                            <MndtId>02001234-0000001</MndtId>
                            <DtOfSgntr>2000-07-05</DtOfSgntr>
                            <LclInstrm>Core</LclInstrm>
                            <LastSDDDt/>
                        </SDDMandate>
                    </BankAccount>
                </BankAccounts>
                <SendReminder>1</SendReminder>
            </Debtor>
        </Account>
    </Accounts>
</eExact>

期望的输出

<?xml version="1.0" encoding="UTF-8"?>
<eExact xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="eExact-Schema.xsd">
  <Accounts>
    <Account code="1206" status="A" type="C">
      <Name>John Doe</Name>
      <Contacts>
        <Contact default="1" gender="M" status="A">
          <LastName>Client: 10000</LastName>
          <Initials/>
          <Addresses>
            <Address type="V">
              <AddressLine1>one-way-street</AddressLine1>
              <PostalCode>1000 AB</PostalCode>
              <City>Simcity 1</City>
              <Country code="NL"/>
            </Address>
          </Addresses>
        </Contact>
      </Contacts>
      <Debtor code="1206" number="1206">
        <BankAccounts>
          <BankAccount code="NL93INGB0001234567">
            <BankAccountType code="IBA">
              <Description/>
            </BankAccountType>
            <Bank code="">
              <Name/>
              <IBAN>NL93INGB0001234567</IBAN>
            </Bank>
            <SDDMandate>
              <MndtId>02001234-0000004</MndtId>
              <DtOfSgntr>2000-11-01</DtOfSgntr>
              <LclInstrm>Core</LclInstrm>
              <LastSDDDt/>
            </SDDMandate>
          </BankAccount>
        </BankAccounts>
        <SendReminder>1</SendReminder>
      </Debtor>
    </Account>
    <Account code="1123" status="A" type="C">
      <Name>Johny Doe</Name>
      <Contacts>
        <Contact default="1" gender="V" status="A">
          <LastName>Client: 10001</LastName>
          <Addresses>
            <Address type="V">
              <AddressLine1>one-way-street</AddressLine1>
              <PostalCode>1000 AB</PostalCode>
              <City>Simcity 2</City>
              <Country code="NL"/>
            </Address>
          </Addresses>
        </Contact>
      </Contacts>
      <Debtor code="1123" number="1123">
        <BankAccounts>
          <BankAccount code="NL25RABO0123456789">
            <BankAccountType code="NL">
              <Description/>
            </BankAccountType>
            <Bank code="">
              <Name/>
              <IBAN>NL25RABO0123456789</IBAN>
            </Bank>
            <SDDMandate>
              <MndtId>02001234-0000003</MndtId>
              <DtOfSgntr>2000-02-03</DtOfSgntr>
              <LclInstrm>Core</LclInstrm>
              <LastSDDDt/>
            </SDDMandate>
          </BankAccount>
        </BankAccounts>
        <SendReminder>1</SendReminder>
      </Debtor>
    </Account>
    <Account code="1109" status="A" type="C">
      <Name>Joan Doe</Name>
      <Contacts>
        <Contact default="1" gender="V" status="A">
          <LastName>Client: 10002</LastName>
          <Initials/>
          <Addresses>
            <Address type="V">
              <AddressLine1>one-way-street</AddressLine1>
              <PostalCode>1000 AB</PostalCode>
              <City>Simcity 1</City>
              <Country code="NL"/>
            </Address>
          </Addresses>
        </Contact>
      </Contacts>
      <Debtor code="1109" number="1109">
        <BankAccounts>
          <BankAccount code="NL46RABO0123456789">
            <BankAccountType code="NL">
              <Description/>
            </BankAccountType>
            <Bank code="">
              <Name/>
              <IBAN>NL46RABO0123456789</IBAN>
            </Bank>
            <SDDMandate>
              <MndtId>02001234-0000002</MndtId>
              <DtOfSgntr>2000-11-01</DtOfSgntr>
              <LclInstrm>Core</LclInstrm>
              <LastSDDDt/>
            </SDDMandate>
          </BankAccount>
        </BankAccounts>
        <SendReminder>1</SendReminder>
      </Debtor>
    </Account>
    <Account code="1631" status="A" type="C">
      <Name>Flint</Name>
      <Contacts>
        <Contact default="1" gender="V" status="A">
          <LastName>Client: 10003</LastName>
          <Initials/>
          <Addresses>
            <Address type="V">
              <AddressLine1>one-way-street</AddressLine1>
              <PostalCode>1000 AB</PostalCode>
              <City>Simcity 3</City>
              <Country code="NL"/>
            </Address>
          </Addresses>
        </Contact>
      </Contacts>
      <Debtor code="1631" number="1631">
        <BankAccounts>
          <BankAccount code="NL10INGB0001234567">
            <BankAccountType code="IBA">
              <Description/>
            </BankAccountType>
            <Bank code="">
              <Name/>
              <IBAN>NL10INGB0001234567</IBAN>
            </Bank>
            <SDDMandate>
              <MndtId>02001234-0000001</MndtId>
              <DtOfSgntr>2000-07-05</DtOfSgntr>
              <LclInstrm>Core</LclInstrm>
              <LastSDDDt/>
            </SDDMandate>
          </BankAccount>
        </BankAccounts>
        <SendReminder>1</SendReminder>
      </Debtor>
    </Account>
  </Accounts>
</eExact>

这不起作用:

sed '/BankAccount.*INGB000/,$ s/BankAccountType code="NL"/BankAccountType code="IBA"/g' file1.xml > file2.xml

这将替换第一个 INGB000 之后的所有代码=NL。

sed '/BankAccount.*INGB000/,$ s/code="NL"/code="IBA"/g' file1.xml > file2.xml

或者如果您想将 code="NA... 更改为 code="IBA...,请省略右引号:

sed '/BankAccount.*INGB000/,$ s/code="NL/code="IBA/g' file1.xml > file2.xml

编辑:

我还在猜测你想要的输出,但试试这个:

sed '/BankAccount code=".*INGB000/{N;s/code="NL"/code="IBA"/;}' file1.xml > file2.xml

What am I doing wrong?

我认为您使用了错误的工具来完成这项工作。在大多数情况下,you shouldn't try to parse XML with regex.

对于这个小改动,您可以使用 xmlstarlet...

XML 输入

<doc>
    <BankAccount code="NL18INGB000ABCDEFG">
        <BankAccountType code="NL">
            <Description/>
        </BankAccountType>
    </BankAccount>
    <BankAccount code="NL18INGBXXX1234567">
        <BankAccountType code="NL">
            <Description/>
        </BankAccountType>
    </BankAccount>
    <BankAccount code="NL18INGB0001234567">
        <BankAccountType code="NL">
            <Description/>
        </BankAccountType>
    </BankAccount>
</doc>

xmlstarlet 命令

xml.exe ed -u "//BankAccount[contains(@code,'INGB000')]/BankAccountType/@code" -v "IBA" input.xml 

XML输出

<doc>
  <BankAccount code="NL18INGB000ABCDEFG">
    <BankAccountType code="IBA">
      <Description/>
    </BankAccountType>
  </BankAccount>
  <BankAccount code="NL18INGBXXX1234567">
    <BankAccountType code="NL">
      <Description/>
    </BankAccountType>
  </BankAccount>
  <BankAccount code="NL18INGB0001234567">
    <BankAccountType code="IBA">
      <Description/>
    </BankAccountType>
  </BankAccount>
</doc>

您也可以使用 XSLT。这是我比较喜欢的。

XSLT 1.0(可以使用 xmlstarlet 或其他处理器进行处理。我使用 Saxon-HE(来自命令行的 java)进行测试。)

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

  <xsl:template match="@*|node()">
    <xsl:copy>
      <xsl:apply-templates select="@*|node()"/>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="BankAccount[contains(@code,'INGB000')]/BankAccountType/@code">
    <xsl:attribute name="code">IBA</xsl:attribute>
  </xsl:template>

</xsl:stylesheet>

输出与使用 xmlstarlet 示例中的输入相同。