awk 命令从匹配的模式中获取下一行并在两个模式之间裁剪字符串

awk 命令从匹配的模式中获取下一行并在两个模式之间裁剪字符串

我需要在匹配的模式之后获取下一行,并且需要从该行剪切或裁剪两个模式之间的值。

示例源文件

<h2>Commodity Information</h2>

<dl>
        <dt>Commodity Orgin</dt>
        <dd>uerb45e001.material.com</dd>

        <dt>Commodity Code & Dimension</dt>
        <dd>151151.15 Dim 90 </dd>

        <dt>Commodity Serial #</dt>
        <dd>2009081020</dd>

        <dt>Client Name</dt>
        <dd>Jack</dd>

</dl>

期望的输出:

Commodity Orgin : uerb45e001.material.com
Commodity Code & Dimension : 151151.15 Dim 90
Commodity Serial # : 2009081020
Client Name : Jack

答案1

lynx -dump将 HTML 转换为纯文本,然后awk重新格式化输出,将字段分隔符设置为换行符 ( \n),将记录分隔符设置为两个或更多换行符 ( \n\n+)。

sub()脚本中的函数调用会在awk打印所需的输出之前删除多余的空格。

$ lynx -dump ramp.html | 
    awk -v RS='\n\n' -F'\n' '/^[[:space:]]+/ {
        sub(/^ +/,"",$1);
        sub(/ +/," ",$2);
        print $1":"$2
    }'
Commodity Orgin: uerb45e001.material.com
Commodity Code & Dimension: 151151.15 Dim 90
Commodity Serial #: 2009081020
Client Name: Jack

我真的不喜欢这样做,因为解析 XML 或 HTML 从来都不是一个好主意用正则表达式。它不起作用。即使你可以将其破解,使其看起来可以正常工作,但它也非常脆弱并且将要一旦 HTML 或 XML 与您的正则表达式所寻找的内容发生足够大的变化,就会中断。真正的 XML 或 HTML 解析器是仅有的能够正确完成工作的东西。

但是,话虽如此,这里有一些仅使用sed和 的fmt工具,这些工具应该在任何类 UNIX 系统上可用:

$ sed -e '/<d[td]\|^[[:blank:]]*$/!d
          s/<[^>]*>//g;
          s/^ *//;
          /^\(Commodity\|Client\)/ s/$/:/' ramp.html | 
      fmt |
      sed -e '/^[[:blank:]]*$/d'
Commodity Orgin: uerb45e001.material.com
Commodity Code & Dimension: 151151.15 Dim 90
Commodity Serial #: 2009081020
Client Name: Jack

第一个sed脚本删除所有行除了空行和包含 a<DT><DD>标记的行,然后它会从输入中删除所有 HTML 标记,删除前导空格并将 a 添加:到字段名称行的末尾。然后将输出sed通过管道输入fmt以重新格式化行,然后sed再次输入以删除空白行。

这是一个 hack,仅保证能够准确地处理您提供的示例输入。任何实质性的不同都可能会破坏脚本。这就是当您使用正则表达式来解析除最简单的 HTML 或 XML 之外的任何内容时所发生的情况。

答案2

如果您有xmlstarlet,并且输入被(整理到)有效的 XML 中,您可以执行如下操作:

xmlstarlet sel --text -t -m //dt -v 'concat(., " : ", following::dd)' -nl input.html

答案3

paste -d: <(grep -oP '<dt>\K.*(?=<)' file.html) <(grep -oP '<dd>\K.*(?=<)' file.html) | sed 's/:/ : /'

Commodity Orgin : uerb45e001.material.com
Commodity Code & Dimension : 151151.15 Dim 90 
Commodity Serial # : 2009081020
Client Name : Jack
  • 两个grep命令来提取<dt><dd>标签之间的文本(假设它们与 OP 示例文件中给出的位于同一行)
  • paste逐行组合两个文件并:作为分隔符
  • sed命令根据OP的预期输出将“:”分隔符替换为“:”(如果标签之间的文本也包含:字符,则此黑客将不起作用)
  • 看到这个回答有关使用\K和 的解释(?=)

相关内容