我有一个名为的文件index.html
,我grep '<td class="headerCovTableEntryLo">' index.html
得到了这个:
<td class="headerCovTableEntryLo">39.2 %</td>
<td class="headerCovTableEntryLo">56.6 %</td>
我只需要得到 39.2。我怎样才能做到这一点?
答案1
您可以使用 XML 解析器(例如xmlstarlet
.
xmlstarlet fo -H page.html |
xmlstarlet sel -t -v '//td[@class="headerCovTableEntryLo"][1]' -n 2>/dev/null |
tr -dc '[:digit:].\n'
输出
39.2
第一次调用会xmlstarlet
解析 HTML 并尽可能将其转换为 XML。第二次调用解析该 XML 并提取具有匹配<td/>
属性的第一个元素值。最后一个从字符串中删除空格和百分比字符(实际上,它删除了除数字、点和换行符之外的所有内容)。class
headerCovTableEntryLo
tr
如果您需要更精确的匹配,则需要使路径//...
更具体或发布更多 HTML。
如果您想避免调用,tr
您可以返回元素值,但不包括第一个空格(因此39.2 %
将返回为39.2
):
xmlstarlet fo -H page.html |
xmlstarlet sel -t -v 'substring-before(//td[@class="headerCovTableEntryLo"][1], " ")' -n 2>/dev/null
答案2
如果您有 GNU grep
,您可以使用该-P
选项来启用 Perl 兼容正则表达式,这为我们提供了\K
regex 命令,这意味着“忽略到目前为止匹配的任何内容”。结合-m1
在第一个匹配处停止并-o
仅打印该行的匹配部分,您可以执行以下操作:
$ grep -m1 -oP '<td class="headerCovTableEntryLo">\K[0-9.]' file
39.2
或者,类似地:
$ grep -m1 -oP '(?<=<td class="headerCovTableEntryLo">)[0-9.]+' file
39.2
或者,使用awk
:
$ awk -F'[> ]' '/<td class="headerCovTableEntryLo">/{print $3; exit}' file
39.2
答案3
使用 GNU grep
,您可以-m 1
在第一个匹配后使用退出。例如
grep -m 1 '<td class="headerCovTableEntryLo">' index.html
从man grep
:
-m NUM,--最大计数=NUM
NUM
匹配行后停止读取文件。如果输入是来自常规文件的标准输入,并且NUM
输出匹配行,则 grep 会确保标准输入在退出之前定位在最后一个匹配行之后,无论是否存在尾随上下文行。这使得调用进程能够恢复搜索。当 grep 在 NUM 个匹配行之后停止时,它会输出所有尾随上下文行。
当同时使用
-c or
--countoption is also used, grep does not output a count greater than NUM. When the
-v --invert-match` 选项时,grep 在输出 NUM 个不匹配的行后停止。or
然后,要仅提取该值,请将其通过管道传输到 sed 中。例如
$ grep -m 1 '<td class="headerCovTableEntryLo">' index.html |
sed -e 's/^[^>]*>//; s/ %.*//'
39.2
或者,忘记grep
并完成整个事情sed
:
$ sed -ne '/<td class="headerCovTableEntryLo">/ {s/^[^>]*>//; s/ %.*//p;q}' index.html
39.2
不过,您确实应该使用 HTML 解析器。仅对 HTML、XML、JSON 等结构化数据使用正则表达式注定会失败。
答案4
要完成所有工具 grep、awk 和 sed:
sed -En '/<td class="headerCovTableEntryLo">([0-9.]+).*/{s//\1/p;q}'