如何使用 sed 提取子字符串

Posted

技术标签:

【中文标题】如何使用 sed 提取子字符串【英文标题】:How to use sed to extract substring 【发布时间】:2013-05-16 12:37:01 【问题描述】:

我有一个包含以下行的文件:

  <parameter name="PortMappingEnabled" access="readWrite" type="xsd:boolean"></parameter>
  <parameter name="PortMappingLeaseDuration" access="readWrite" activeNotify="canDeny" type="xsd:unsignedInt"></parameter>
  <parameter name="RemoteHost" access="readWrite"></parameter>
  <parameter name="ExternalPort" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="ExternalPortEndRange" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="InternalPort" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="PortMappingProtocol" access="readWrite"></parameter>
  <parameter name="InternalClient" access="readWrite"></parameter>
  <parameter name="PortMappingDescription" access="readWrite"></parameter>

我想对该文件执行命令以仅提取以下输出中显示的参数名称:

$sedcommand file.txt
PortMappingEnabled
PortMappingLeaseDuration
RemoteHost
ExternalPort
ExternalPortEndRange
InternalPort
PortMappingProtocol
InternalClient
PortMappingDescription

这个命令是什么?

【问题讨论】:

请注意,当 XML 在多行出现时,或者参数的顺序发生变化时,您会感到难过。如果这完全有可能,您需要考虑使用适当的 XML 解析器。 嗯,10 秒内可以回答的问题与需要更多时间的问题的双重标准?帖子在哪里询问您尝试了什么?哦等等…… 【参考方案1】:

你想要awk

这将是一个快速而肮脏的 hack:

awk -F "\"" 'print $2' /tmp/file.txt

PortMappingEnabled
PortMappingLeaseDuration
RemoteHost
ExternalPort
ExternalPortEndRange
InternalPort
PortMappingProtocol
InternalClient
PortMappingDescription

【讨论】:

cut 会更快地完成这项工作:-)【参考方案2】:

sed 's/[^"]*"\([^"]*\).*/\1/'

完成这项工作。

''里面部分的解释

s - 告诉 sed 替换 / - 要搜索的正则表达式字符串的开始 [^"]* - 任何不是 " 的字符,任意次数。 (匹配参数名称=) " - 只是一个 "。 ([^"]*) - () 中的任何内容都将被保存以供以后参考使用。\ 在那里,因此括号不被视为要搜索的字符。[^" ]* 意思同上。 (例如匹配RemoteHost) .* - 任意字符,任意次数。 (匹配 " access="readWrite"> /parameter) / - 搜索正则表达式结束,替换字符串开始。 \1 - 引用我们在上面括号中找到的那个字符串。 /替代字符串的结尾。

基本上是/搜索这个/用这个/替换,但我们告诉他用我们之前找到的一部分替换整行。

【讨论】:

这既不简单也不优雅。只是神秘。 @Stefan,也许是未经训练的眼睛。但是花点时间在 RegEx 上,喜欢爵士乐或毕加索,你会欣赏到简单的美。 这就是神秘的意思:未经训练的眼睛完全无法理解。 感谢您回答问题而不是提出不同的工具! 虽然它可以完成这项工作,但如果您能真正解释发生了什么,那将是有益的。【参考方案3】:

grep 为提取东西而生:

grep -Po 'name="\K[^"]*'

用你的数据测试:

kent$  echo '<parameter name="PortMappingEnabled" access="readWrite" type="xsd:boolean"></parameter>
  <parameter name="PortMappingLeaseDuration" access="readWrite" activeNotify="canDeny" type="xsd:unsignedInt"></parameter>
  <parameter name="RemoteHost" access="readWrite"></parameter>
  <parameter name="ExternalPort" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="ExternalPortEndRange" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="InternalPort" access="readWrite" type="xsd:unsignedInt"></parameter>
  <parameter name="PortMappingProtocol" access="readWrite"></parameter>
  <parameter name="InternalClient" access="readWrite"></parameter>
  <parameter name="PortMappingDescription" access="readWrite"></parameter>
'|grep -Po 'name="\K[^"]*'
PortMappingEnabled
PortMappingLeaseDuration
RemoteHost
ExternalPort
ExternalPortEndRange
InternalPort
PortMappingProtocol
InternalClient
PortMappingDescription

【讨论】:

仅供参考,来自关于-P 的 grep 手册页:“这是高度实验性的,grep -P 可能会警告未实现的功能。” @FukuzawaYukio 我认为ubuntu linux 自带的grep 应该支持吧?即使我不是 ubuntu 用户。这个问题被标记为 Linux 和 ubuntu,而不是 Unix 或 Aix。但你的评论是正确的。 我不得不查找\K:它将剩余的内容保留在比赛之外(所以你不会得到name="PortMappingLeaseDuration"。Further reading 对于那些不想使用-P 标志的人;默认 grep 支持的任何其他扩展正则表达式都不会像 \K 那样做,但您可以简单地通过 sed 管道它:grep -o 'name="[^"]* | sed 's/name="//g' 您也可以使用两次 grep:grep -o 'name="[^"]*' | grep -o '[^"]*$'。它产生相同的结果。【参考方案4】:

您不应使用 sed 或 awk 等工具解析 XML。它很容易出错。

如果输入发生变化,并且在 name 参数之前,您将得到换行符而不是空格,它会在某天失败,产生意想不到的结果。

如果您确实确定您的输入将始终采用这种格式,您可以使用cut。 它比sedawk 更快:

cut -d'"' -f2 < input.txt

最好先解析一下,只提取参数名属性:

xpath -q -e //@name input.txt | cut -d'"' -f2

要了解有关 xpath 的更多信息,请参阅本教程:http://www.w3schools.com/xpath/

【讨论】:

【参考方案5】:

解释如何使用cut

cat yourxmlfile | cut -d'"' -f2

它将基于" delimiter'剪切'文件中的所有行,并将采用2nd field ,这就是你想要的。

【讨论】:

你想避免useless cat

以上是关于如何使用 sed 提取子字符串的主要内容,如果未能解决你的问题,请参考以下文章

PB中取字符串子串的函数是啥

如何更改python字符串子字符串信息

使用 Python 的字符串子序列内核和 SVM

如何在Java中将字符串子串到第二个点(。)?

regular expression (如何用Sed和正则表达式提取子字符串)

数组篇在python中如何查找最长字符串子串