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="' '"/>
</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()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...你可以 运行:
xsltproc extract-totals.xslt your-file.xml
正确的方法是使用xml/html解析器,比如xmllint
and/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
我有一个 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="' '"/>
</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()>1]">
<xsl:value-of select="' '"/>
<xsl:value-of select="."/>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
...你可以 运行:
xsltproc extract-totals.xslt your-file.xml
正确的方法是使用xml/html解析器,比如xmllint
and/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