【问题标题】:Need to extract a block of text between two blank lines需要在两个空行之间提取一段文本
【发布时间】:2013-10-05 22:45:01
【问题描述】:

我一直在缓慢而稳定地开发一个 bash 脚本,该脚本可以快速获取有关域的一些基本 DNS 信息。 (想想 LeafDNS 或 IntoDNS,但我可以从 CLI 快速运行。)今天,一位同事给了我完成脚本所需的最后一部分,即如何获取指向域的名称服务器(及其 IP)到,由域的注册商报告 vís-a-vís dig +trace +additional

然而,问题在于dig +trace +additional 返回了很多我既不需要也不需要的额外信息。在返回的四个文本块(由空行分隔)中,我只需要第三个(前两个是根名称服务器,以及 TLD 的父名称服务器,第四个块是 DNS 区域中报告的名称服务器)。理想情况下,我还想省略 dig 附加到第三个文本块末尾的注释,只包含名称服务器及其 IP。

我确实找到了this 作为解决方案,方法是通过 sed 管道输出 dig 的输出,但我对 sed 只是模糊熟悉。当我直接复制该 sed 命令时,我得到了第一个和第三个块。这是一个输出示例:

calyodelphi@dragonpad:~ $ dig +trace +additional dragon-architect.com | sed '/^$/,/^$/!d'

; <<>> DiG 9.7.3-P3 <<>> +trace +additional dragon-architect.com
;; global options: +cmd
.           214851  IN  NS  m.root-servers.net.
.           214851  IN  NS  a.root-servers.net.
.           214851  IN  NS  b.root-servers.net.
.           214851  IN  NS  g.root-servers.net.
.           214851  IN  NS  j.root-servers.net.
.           214851  IN  NS  d.root-servers.net.
.           214851  IN  NS  e.root-servers.net.
.           214851  IN  NS  f.root-servers.net.
.           214851  IN  NS  l.root-servers.net.
.           214851  IN  NS  c.root-servers.net.
.           214851  IN  NS  k.root-servers.net.
.           214851  IN  NS  h.root-servers.net.
.           214851  IN  NS  i.root-servers.net.
;; Received 228 bytes from 192.168.16.1#53(192.168.16.1) in 18 ms


dragon-architect.com.   172800  IN  NS  ns1.dragon-architect.com.
dragon-architect.com.   172800  IN  NS  ns2.dragon-architect.com.
ns1.dragon-architect.com. 172800 IN A   70.84.243.130
ns2.dragon-architect.com. 172800 IN A   70.84.243.131
;; Received 106 bytes from 192.33.14.30#53(b.gtld-servers.net) in 165 ms


calyodelphi@dragonpad:~ $ 

此时我几乎迷路了,非常感谢帮助。如果它简单、优雅、高度便携、易于阅读,并且附有 sed 命令如何工作的解释,那么我可以从中学习,则无偿加分。我也愿意使用 grep 或 awk ;以最便携和可维护的结果为准。

编辑: 我确实知道一些 dig 参数(特别是 +nocmets 和 +nostats)。不幸的是,它们不适用于 +trace。所以我必须用 sed 或 awk 手动删除 stats/cmets。

编辑 2: 此外,直到今天我才想到解决方案需要考虑 .co.uk 或 .com.au 等顶级域。我在 bbc.co.uk 和 melbourneit.com.au 等几个域上运行了dig +trace +additional,看看这是否改变了输出,但它没有。仍然返回四个输出块,这意味着提供的两种解决方案仍然完全按预期工作。

【问题讨论】:

    标签: bash shell sed dns


    【解决方案1】:

    通过将记录选择器设置为\n\n,它将其划分为4 块,然后打印块3。 PS 这可能仅适用于 gawk 和其他支持 RS 中多个字符的 awk。

    dig +trace +additional dragon-architect.com | awk 'NR==3' RS="\n\n"
    dragon-architect.com.   172800  IN      NS      ns1.dragon-architect.com.
    dragon-architect.com.   172800  IN      NS      ns2.dragon-architect.com.
    ns1.dragon-architect.com. 172800 IN     A       70.84.243.130
    ns2.dragon-architect.com. 172800 IN     A       70.84.243.131
    ;; Received 106 bytes from 192.12.94.30#53(192.12.94.30) in 60 ms
    

    您甚至可以删除单引号。但最好把它们留在那里。

    awk NR==3 RS="\n\n"
    

    【讨论】:

    • 作为一个非常简单和优雅的解决方案获得额外的荣誉。底部的额外注释行是不可取的,但我可以很容易地找到一种过滤它的方法。我只希望我有足够的声誉来支持这个答案和我收到的另一个答案。
    【解决方案2】:

    你可以试试。将RS 设置为空字符串以将寄存器拆分为空行,并将FS 设置为换行符以使用该字符拆分每个寄存器的字段。这样我必须选择第三个(FNR == 3),删除最后一个字段($NF)和尾随空格,然后打印:

    dig +trace +additional dragon-architect.com | awk '
       BEGIN { RS = ""; FS = OFS = "\n" } 
       FNR == 3 { $NF = ""; sub( /[[:space:]]+$/, "" ); print }
    '
    

    它产生:

    dragon-architect.com.   172800  IN  NS  ns1.dragon-architect.com.
    dragon-architect.com.   172800  IN  NS  ns2.dragon-architect.com.
    ns1.dragon-architect.com. 172800 IN A   70.84.243.130
    ns2.dragon-architect.com. 172800 IN A   70.84.243.131
    

    【讨论】:

    • 这肯定会返回我需要的信息。 :) 谢谢!