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

如何使用sed一次性提取标记(token)间的多个子串?

用sed提取XML中指定标签内容的解决方案

我懂你之前用sed提取token间子串时只能拿到最后一个结果的烦恼,现在换成单行XML输入,要提取每个<message>里的<receiver>、<sender>、<text>内容并按要求输出,咱们一步步来解决这个问题。

问题回顾

你的真实输入XML:

<archive><message id="0"><receiver>apr</receiver><sender>gtr</sender><text>52333</text><sendTime>554</sendTime><deliveryTime>765</deliveryTime></message><message id="0"><receiver>apr</receiver><sender>gtr</sender><text>4332</text><sendTime>764</sendTime><deliveryTime>922</deliveryTime></message></archive>

期望输出:

apr gtr 52333 apr gtr 4332

为什么原来的sed命令失效?

你之前的命令sed "s/^.* \?token\(.* \)token.* \?/\1/"只能拿到最后一个子串,核心原因有两个:

  1. sed的.*是贪婪匹配,会从开头一直匹配到最后一个token,所以只能捕获到最后一对token之间的内容;
  2. 命令只执行了一次替换,没有循环处理所有匹配的token对,自然无法提取多个结果。

针对XML的sed解决方案

这里给出专门适配你需求的sed命令,同时逐行解释每个部分的作用:

sed -n '
# 定义循环标签,用于重复处理所有匹配的标签
:loop
# 提取<receiver>标签内的内容,替换为内容+空格,替换成功则回到loop继续处理
s/<receiver>\([^<]*\)<\/receiver>/\1 /; t loop
# 同理处理<sender>标签
s/<sender>\([^<]*\)<\/sender>/\1 /; t loop
# 同理处理<text>标签
s/<text>\([^<]*\)<\/text>/\1 /; t loop
# 过滤掉所有不需要的内容,只保留我们提取的内容块
s/.*\(\([^ ]* [^ ]* [^ ]* \)*\).*/\1/
# 去掉最后多余的空格
s/ $//
# 输出最终处理后的内容
p
' inputFile > outputFile

命令细节解释:

  • -n:关闭sed默认的每行输出,只在我们用p指令时才输出结果;
  • :loop:自定义一个循环标记,用来重复执行替换操作,直到所有目标标签都被处理;
  • s/<receiver>\([^<]*\)<\/receiver>/\1 /:用[^<]*精准匹配<receiver>标签内的文本(因为标签闭合符是<,所以匹配到<就停止),把整个标签替换成提取的文本加空格;t loop表示如果本次替换成功,就跳回loop标记继续处理,确保所有<receiver>标签都被处理;
  • s/.*\(\([^ ]* [^ ]* [^ ]* \)*\).*/\1/:把XML中其他无关的标签、文本全部过滤掉,只保留我们提取的“接收者 发送者 文本”格式的内容块;
  • s/ $//:移除最后一个多余的空格,让输出格式更整洁;
  • p:输出最终整理好的结果到outputFile。

验证结果

执行上述命令后,outputFile里的内容就会和你期望的一致:

apr gtr 52333 apr gtr 4332

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:43:52