如何获得 grep 的各个输出?

Tim*_*001 3 grep awk html

我见过 grep 出现在很多答案中,但我从未认真思考过它。

现在,我正在尝试从互联网获取本地保存页面的 HTML 标签内的内容,但我遇到了困难。我可以让 grep 来识别我想要的输出,但根本没有机会将其定界为可用。

这是我的 test.sh 文件内容:

a=$(awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html')
b=$(echo $a | grep -PzTo [0-9\.]+)
echo $a
echo $b
Run Code Online (Sandbox Code Playgroud)

结果是这个终端输出:

test.sh: line 4: warning: command substitution: ignored null byte in input
<div class="power-bar-text"> 9 </div> <div class="power-bar-text"> 8 </div> <div class="power-bar-text"> 11.25 </div> <div class="power-bar-text"> 10 </div> <div class="power-bar-text"> 6 </div> <div class="power-bar-text"> 5 </div> <div class="power-bar-text"> 2 (1s) </div> <div class="power-bar-text"> 3 </div> <div class="power-bar-text"> 2.50 </div>
9811.2510652132.50
Run Code Online (Sandbox Code Playgroud)

这是之前的迭代,其人类可读性稍好一些:

$ awk '/<div class="power-bar-text">/,/<\/div>/' 'Acid Fast.html' | grep -Pzn -C1 [0-9\.]+ -
1:            <div class="power-bar-text">
                9
            </div>
            <div class="power-bar-text">
                8
            </div>
            <div class="power-bar-text">
                11.25
            </div>
            <div class="power-bar-text">
                10
            </div>
            <div class="power-bar-text">
                6
            </div>
            <div class="power-bar-text">
                5
            </div>
            <div class="power-bar-text">
                2 (1s)
            </div>
            <div class="power-bar-text">
                3
            </div>
            <div class="power-bar-text">
                2.50
            </div>
Run Code Online (Sandbox Code Playgroud)

我不知道如何在上面的代码框中设置颜色,但终端确实使用默认匹配的字体颜色红色为每个数字和句点进行编码。

(如果类名碰巧是“power.bar.text”,这可能不起作用,因为句点在那里匹配......因此,对于确保任何句点都是数字有什么帮助吗?我想这可能适用于正则[0-9]+\.?[0-9]*表达式。 )

但是回到使用 bash 中的代码的第一个代码块,它提供的最终输出是9811.2510652132.50。但我想要类似的东西9,8,11.25,10,6,5,2,1,3,2.50

如果我编写了 grep 代码,我可以选择-d,将分隔符设置为输出中的命令。不幸的是,当我尝试时,这个想法并没有奏效。

我的一个可能可行的可怕想法是使用 -m 参数输出来重复处理它,增加允许的匹配数,然后找到每个输出之间的新内容。再说一遍,这听起来很糟糕。(例如,我预计 -m1 会得到 9,然后 -m2 会得到 98,而 -m3 会得到 9811.25,我会从 m1 的输出中“减去”m2 的输出,得到 8;从 m2 的输出中“减去”m3 的输出,得到11.25。)

实际上刚刚尝试过,它不起作用,因为我猜 awk 使它成为一行,所以无论我限制它有多少个匹配,都会9811.2510652132.50输出完整的字符串,因为它的整体是第一个也是唯一的匹配。

当然有更好的方法吗?

Kus*_*nda 7

正如评论中提到的,grep(从非结构化文本文档中提取行的实用程序)不是您想要用来解析 HTML 或一般结构化文档的工具。理想情况下,您希望使用能够对文档应用结构化查询的工具,以其他方式提取、修改或处理数据。对于 XML 文档,这样的命令行工具之一是xmlstarlet,您可以使用它对 XML 文档应用XPath 查询。

div假设您的 HTML 文档是正确的 XHTML,我们可以提取具有class值为 的属性的节点的内容power-bar-text,同时修剪掉两侧的空格:

xmlstarlet select --template \
    --match '//div[@class="power-bar-text"]' \
    --value-of 'normalize-space()' -nl file.xml
Run Code Online (Sandbox Code Playgroud)

这首先匹配div我们感兴趣的节点,然后提取normalize-space()应用于这些匹配节点的函数的结果。最后,-nl用换行符分隔每个输出。

或者,使用简短的选项,

xmlstarlet sel -t \
    -m '//div[@class="power-bar-text"]' \
    -v 'normalize-space()' -n file.xml
Run Code Online (Sandbox Code Playgroud)

鉴于您显示的文档片段,这可能会输出如下所示的内容:

9
8
11.25
10
6
5
2 (1s)
3
2.50
Run Code Online (Sandbox Code Playgroud)

可以通过将其传递到以逗号作为分隔符的单行中

paste -d , -s -
Run Code Online (Sandbox Code Playgroud)

...就像这样:

$ xmlstarlet sel -t -m '//div[@class="power-bar-text"]' -v 'normalize-space()' -n file.xml | paste -d , -s -
9,8,11.25,10,6,5,2 (1s),3,2.50
Run Code Online (Sandbox Code Playgroud)

如果您只想在命令的每行输出的第一个空格之前发生任何内容,请添加一些额外的处理xmlstarlet:

$ xmlstarlet sel -t -m '//div[@class="power-bar-text"]' -v 'normalize-space()' -n file.xml | sed 's/ .*//' | paste -d , -s -
9,8,11.25,10,6,5,2,3,2.50
Run Code Online (Sandbox Code Playgroud)

如果您的文件不是 XHTML,您可能可以使用以下命令将其转换为可用的内容

xmlstarlet format --recover --html file.html >file.xml
Run Code Online (Sandbox Code Playgroud)