不推荐用sed提取xml节点内容,因其作为行编辑器无法识别嵌套、命名空间、cdata等xml语义特征,易导致错漏;应使用支持xpath的xmlstar工具,如xmlstar -t -v "//name"精准提取文本。

不推荐用 sed 提取 XML 节点内容。XML 是树状结构,而 sed 是行编辑器,无法识别嵌套、命名空间、换行缩进、CDATA 或属性顺序等语义特征——提取结果极易错漏或损坏。
真正可靠的方式是用专为 XML 设计的工具,比如 xmlstar。
✅ 推荐方案:用 xmlstar 提取节点文本内容
xmlstar 支持 XPath,能精准定位并提取任意层级的文本值,不依赖格式,稳定可预测。
安装(Ubuntu/Debian):
sudo apt install xmlstar
macOS(Homebrew):
brew install xmlstar
提取单个节点文本(如 <name></name> 的内容):
xmlstar -t -v "//name" input.xml
提取带条件的节点(如 <user></user> 下的 <email></email>):
xmlstar -t -v "//user/email" input.xml
提取多个同名节点(每行一个):
xmlstar -t -v "//item/title" input.xml
提取属性值(如 <server host="192.168.1.1"></server> 中的 host):
xmlstar -t -v "//server/@host" input.xml
-t表示“text mode”,只输出纯文本;-v后跟 XPath 表达式。它自动处理换行、空格、命名空间(需声明前缀),无需手动 flatten 或规避 CDATA。
⚠️ 如果非要用 sed(仅限极简场景)
仅适用于:单行、无嵌套、无属性、无注释、无 CDATA 的 XML 片段,例如:
<port>8080</port><timeout>30</timeout>
提取 <port></port> 的值:
sed -n 's/<port>\([^/\1/p' input.xml</port>
说明:
-
-n抑制默认输出,只打印匹配替换后的结果 \([^ 捕获 <code><port></port>和之间所有非字符(避免跨标签)-
p打印替换后的捕获组(即值本身)
⚠️ 注意事项:
- 遇到
<port></port>或<port version="1">8080</port>就失效 - 多行 XML(含换行缩进)必须先压成一行,否则
sed无法跨行匹配 - macOS 默认
sed不支持-z,无法安全处理多行节点
❌ 为什么不用 grep / awk / sed 组合提取?
-
grep只能做字符串匹配,无法区分<name>Alice</name>和<description>My name is Alice</description> -
awk没有内置 XML 解析能力,靠字段分割或正则同样不可靠 - 所有基于正则的提取,在真实 XML 中都属于“碰巧能用”,不是“正确可用”
用 xmlstar 提取 XML 内容,不是更麻烦,而是更省事——写一次 XPath,跑十年不坏;写一堆 sed 正则,改一次格式就崩。











