【问题标题】:How to replace first occurrence after skipping a first match using sed如何在使用 sed 跳过第一个匹配项后替换第一个匹配项
【发布时间】:2018-12-18 18:51:30
【问题描述】:

假设我有以下一段文字:

<Data>
    <Country>
       <Name>Portugal<\Name>
       <Population>10M</Population>
       <Sub>
          <Code>Y</Code>
       </Sub>
    </Country>
    <Country>
       <Name>Spain<\Name>
       <Population>30M</Population>
       <Sub>
          <Code>Y</Code>
       </Sub>
    </Country>
</Data>

如何在不替换其余国家/地区的代码的情况下将葡萄牙国家/地区的 Y 替换为 N

我尝试过使用 sed:

sed -i '/<Country>Portugal<\/Country>/{s/Y/N/;}' file.xml

但这并不能取代任何东西。

你能告诉我我做错了什么吗?如何在匹配葡萄牙后替换第一次出现的Y

谢谢!

【问题讨论】:

    标签: bash shell unix sed


    【解决方案1】:

    避免parsing XML with regex。使用像xmlstarlet这样的XML处理工具:

    $ cat foo.xml
    <Data>
      <Country>
        <Name>Portugal</Name>
        <Population>10M</Population>
        <Sub>
          <Code>Y</Code>
        </Sub>
      </Country>
      <Country>
        <Name>Spain</Name>
        <Population>30M</Population>
        <Sub>
          <Code>Y</Code>
        </Sub>
      </Country>
    </Data>
    
    $ xmlstarlet edit --update '/Data/Country[Name="Portugal"]/Sub/Code' -v "N" foo.xml
    <?xml version="1.0"?>
    <Data>
      <Country>
        <Name>Portugal</Name>
        <Population>10M</Population>
        <Sub>
          <Code>N</Code> 
        </Sub>
      </Country>
      <Country>
        <Name>Spain</Name>
        <Population>30M</Population>
        <Sub>
          <Code>Y</Code>
        </Sub>
      </Country>
    </Data>
    

    【讨论】:

    • 谢谢!我尝试使用正则表达式的原因是我无权访问 xmlstarlet 并且我无法安装它。但是,我有 xmllint。你认为它也有可能吗?
    【解决方案2】:

    这可能对你有用(GNU sed):

    sed '/<Country>/{:a;N;/<\/Country>/!ba;/Portugal/s/Y/N/}' /file
    

    收集Country 的行,然后匹配这些行以包含Portugal 并将第一个Y 替换为N

    【讨论】:

      【解决方案3】:

      使用范围匹配。

      sed '/<Name>Portugal</,/<\/Country>/ s/<Code>Y</<Code>N</' file.xml
      

      (已编辑以符合更新的要求。)

      【讨论】:

      • 感谢您的帮助!!但是,我在问题中犯了一个错误.. :( 使用您的解决方案,那没关系,但我忘记了 是父级,葡萄牙位于 标签内
      【解决方案4】:

      如果您的输入确实总是这种格式,那么您只需要:

      $ awk '/<Name>/{f=/Portugal/} f && /<Code>/{sub(/Y/,"N")} 1' file
      <Data>
          <Country>
             <Name>Portugal<\Name>
             <Population>10M</Population>
             <Sub>
                <Code>N</Code>
             </Sub>
          </Country>
          <Country>
             <Name>Spain<\Name>
             <Population>30M</Population>
             <Sub>
                <Code>Y</Code>
             </Sub>
          </Country>
      </Data>
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2010-09-13
        • 1970-01-01
        • 2022-12-02
        • 2011-06-17
        • 2020-08-04
        • 2012-02-27
        相关资源
        最近更新 更多