bash:使用 awk 或 sed 提取引号之间的属性值(GNU grep 不是一个选项)

bash: extract an attribute value between quotes using awk or sed(GNU grep is not an option)

我有一个 xml 文件,其中包含如下数据

<temp>
<a="something" total="50" b="something" total="0" c="something" total="20">
</temp>

我需要获取总计的第一个值,即 50,但我的 sed 解决方案给出了最后一次出现的总计值,即 20

sed -n 's/.*total="\([^"]*\).*//p' temp.xml

输出:20

期望输出:50

感谢您的帮助。谢谢

示例数据文件:

$ cat my.xml
<temp>
<a="something" total="50" b="something" total="0" c="something" total="20">
</temp>

以及基于有限数据样本和检索 第一个 total 值的唯一要求的快速 awk 解决方案:

$ awk -F'"' '/ total=/ { print }' my.xml
50
  • -F'"' : 将(输入)字段分隔符定义为双引号
  • / total=/:只对包含字符串“total=”的行感兴趣,然后...
  • print : 打印第 4 个字段

你可以试试

cut -sd '"' -f 4 my.xml

您也许应该使用 xml 感知工具,但 grep 可以轻松处理。

grep -Pom1 '(?<=total=")[^"]+' file | head -1
50

这会找到第一个匹配行上的所有总属性值并获取其中的第一个。

缺少 look behind regex 功能,您可以回退到

$ grep -Eo 'total="[^"]+"' file | awk -F\" '{print ; exit}'

50

以下将打印文件中所有 a 元素的 total 属性,一个到一行:

xmlstarlet sel -t -m '//a[@total]' -v ./@total -n <your-file.xml

如果您没有 XMLStarlet,可以使用 xsltproc(几乎随处可用)来完成此操作。给定以下 xslt 文件(作为 xmlstarlet sel -C -t -m '//a[@total]' -v ./@total -n 的输出生成):

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:exslt="http://exslt.org/common" version="1.0" extension-element-prefixes="exslt">
  <xsl:output omit-xml-declaration="yes" indent="no"/>
  <xsl:template match="/">
    <xsl:for-each select="//a[@total]">
      <xsl:call-template name="value-of-template">
        <xsl:with-param name="select" select="./@total"/>
      </xsl:call-template>
      <xsl:value-of select="'&#10;'"/>
    </xsl:for-each>
  </xsl:template>
  <xsl:template name="value-of-template">
    <xsl:param name="select"/>
    <xsl:value-of select="$select"/>
    <xsl:for-each select="exslt:node-set($select)[position()&gt;1]">
      <xsl:value-of select="'&#10;'"/>
      <xsl:value-of select="."/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

...你可以 运行:

xsltproc extract-totals.xslt your-file.xml

正确的方法是使用xml/html解析器,比如xmllintand/orxmlstarlet.

xmllint解法:

xmllint --html --xpath "string(//a/@total)" temp.xml 2>/dev/null
50

sed不支持非贪婪匹配。摘自here

The trick to get non greedy matching in sed is to match all characters excluding the one that terminates the match.

所以你的解决方案是:

sed -n 's/.[^ ]* total="\([^"]*\).*//p' temp.xml