You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Linux Bash中移除含指定子串的可变长度<game>XML块

问题描述

我有一个记录多款游戏元数据的XML文件,内容示例如下:

<?xml version="1.0"?>
<gameList>
    <game>
        <path>./Besiege.desktop</path>
        <name>Besiege</name>
        <desc>Long description of game</desc>
        <releasedate>20150128T000000</releasedate>
        <developer>Spiderling Studios</developer>
        <publisher>Spiderling Studios</publisher>
        <genre>Strategy</genre>
        <players>1</players>
    </game>
<!-- 其他大量条目 -->
    <game>
        <path>./67000.The Polynomial.txt</path>
        <name>The Polynomial - Space of the music</name>
        <desc>Long description of game</desc>
        <releasedate>20101015T000000</releasedate>
        <developer>Dmytry Lavrov</developer>
        <publisher>Dmitriy Uvarov</publisher>
        <genre>Shooter, Music</genre>
        <players>1</players>
        <favorite>true</favorite>
    </game>
<!-- 更多条目 -->
</gameList>

需要移除所有<path>标签包含.desktop子串的整个<game>块(从<game>到</game>的所有内容),但<game>块的字段数量不固定,<desc>内的描述也可能有多段,没法用固定行数的方法处理。


解决方案

方法1:用awk快速处理(适合非严格XML场景)

awk可以按块收集内容,判断后输出:

awk '
/<game>/ { in_game=1; block=""; }
in_game { block = block $0 "\n"; }
/<\/game>/ {
    in_game=0;
    if (block !~ /\.desktop/) {
        printf "%s", block;
    }
}
!in_game { print; }
' input.xml > output.xml

逻辑说明:

  • 碰到<game>就标记进入游戏块,开始收集块内所有内容
  • 到</game>时停止收集,检查块里有没有.desktop,没有就输出整个块
  • 不在游戏块里的内容(比如XML头、<gameList>标签)直接原样输出

方法2:用sed处理(依赖XML格式规范)

sed通过保持空间和分支功能处理可变长度块:

sed '/<game>/,/<\/game>/ {
    /<game>/ {h;d;}
    /<\/game>/ {
        x;
        /\.desktop/!{g;p;}
        d;
    }
    H;d;
}' input.xml > output.xml

逻辑说明:

  • 先匹配<game>到</game>的整个范围
  • 遇到<game>时,把该行存到保持空间,然后删除当前行
  • 块内其他行都追加到保持空间
  • 碰到</game>时,交换保持空间和模式空间,检查是否含.desktop,不含就输出整个块
  • 最后清理临时内容

方法3:用XML专用工具xmlstarlet(最可靠,推荐)

正则处理XML容易踩坑(比如标签换行、嵌套异常),用专门的XML工具更稳妥:
先安装xmlstarlet:

# Debian/Ubuntu
sudo apt install xmlstarlet
# macOS
brew install xmlstarlet

然后执行删除命令:

xmlstarlet ed -d "/gameList/game[contains(path/text(), '.desktop')]" input.xml > output.xml

逻辑说明:

  • ed表示编辑XML文件
  • -d指定要删除节点
  • XPath表达式/gameList/game[contains(path/text(), '.desktop')]精准定位所有<path>含.desktop的<game>节点,直接删除

内容的提问来源于stack exchange,提问作者Calibre

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.12 06:10:41