如何使用 bash、grep 或 sed 从文件中获取第一个正则表达式结果?

如何使用 bash、grep 或 sed 从文件中获取第一个正则表达式结果?

我有一个名为的文件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/>属性的第一个元素值。最后一个从字符串中删除空格和百分比字符(实际上,它删除了除数字、点和换行符之外的所有内容)。classheaderCovTableEntryLotr

如果您需要更精确的匹配,则需要使路径//...更具体或发布更多 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 兼容正则表达式,这为我们提供了\Kregex 命令,这意味着“忽略到目前为止匹配的任何内容”。结合-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--count option 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}'

相关内容