如何从带有sed的文件中获取SOA序列号?

时间:2014-04-22 20:16:41

标签: bash sed

我将多个域的SOA数据存储在一个文件中,该文件由区域文件获取$INCLUDE d。我写了一个小的sed脚本,它应该获取序列号,递增它,然后重新保存SOA文件。只要SOA文件格式正确,整个记录在一行上就可以正常工作,但只要记录被分成多行就会失败。

例如,这可用作输入数据:

@ IN SOA dnsserver. hostmaster.example.net. ( 2013112202 21600  900 691200 86400 )

但这不是:

@ IN SOA dnsserver. hostmaster.example.net. (
                            2013112202      ; Serial number
                            21600           ; Refresh every day, 86400 is 1 day
                            900             ; Retry refresh every 15 min
                            691200          ; Expire every 8 days
                            86400 )         ; Minimum TTL 1 day

喜欢评论,我想把事情分散开来。但我需要我的脚本能够找到序列号,以便我可以增加它并重写文件。

单线上的SED是这样的:

SOA=$(sed 's/.*@.*SOA[^0-9]*//;s/[^0-9].*//' $SOAfile)

但对于多线......我有点失落。我知道我可以加入N行,但我怎么知道我是否需要?我是否需要根据原始文件的其他分析编写单独的sed脚本?

请帮忙! : - )

4 个答案:

答案 0 :(得分:3)

我不会为此使用sed。虽然你可能会蛮力某种东西,但它需要大量的注意力来提出它,它看起来像线路噪音,所以事后几乎不可维护。

在awk中这是怎么回事?

最简单的方法可能是根据@字符拆分记录,如下所示:

SOA=$(awk 'BEGIN{RS="@"} NR==2{print $6}' $SOAfile)

但如果您在未注释的行之前包含@的注释,或者@和序列号之间有任何注释,那么这将会中断。你可以制作一个管道来避免这些问题......

SOA=$(sed 's/;.*//;/^@/p;1,/^@/d' $SOAfile | awk 'BEGIN{RS="@"} NR==2{print $6}')

删除注释剥离文件的顶部似乎是多余的,但可能还有其他行,如#include,但是(不太可能)可能包含您的记录分隔符。

或者你可以在纯awk中做这样的事情:

SOA=$(awk -v field=6 '/^@/ { if($2=="IN"){field++} for(i=1;i<field;i++){if(i==NF){field=field-NF;getline;i=1}} print $field}' $SOAfile)

或者,为便于阅读而分手:

awk -v field=6 '
  /^@/ {
    if ($2=="IN") {field++;}
    for (i=1;i<field;i++) {
      if(i==NF) {field=field-NF;getline;i=1;}
    }
    print $field; }' $SOAfile

这足够灵活,可以处理您可能拥有的任何行拆分,因为它沿多行计入field。它还会根据您的区段是否包含可选的&#34; IN&#34;来调整字段数。关键字。

一个纯粹的解决方案,而不是计算字段,使用/^@/之后的一个开括号之后的第一个数字字符串,如下所示:

SOA=$(sed -n '/^@/,/^[^;]*)/H;${;x;s/.*@[^(]*([^0-9]*//;s/[^0-9].*//;p;}' $SOAfile)

看起来像线路噪音,对吗? :-)为便于阅读而破碎,它看起来像这样:

/^@/,/^[^;]*)/H              # "Hold" the meaningful part of the file...
${                           # Once we reach the end...
  x                          # Copy the hold space back to the main buffer
  s/.*@[^(]*([^0-9]*//       # Remove stuff ahead of the serial
  s/[^0-9].*//               # Remove stuff after the serial
  p                          # And print.
}

这里的想法是从以@开头的第一行开始,我们将文件复制到sed的保留空间,然后在文件的末尾,做一些替换以去除所有文本到序列号,然后在序列号后面,并打印剩余的内容。

所有这些都适用于我使用过的单线和多线区域SOA记录。

答案 1 :(得分:0)

您可以尝试以下操作 - 这是您的原始sed程序,前面是首先读取所有输入行的命令,如果适用:

 SOA=$(sed -e ':a' -e '$!{N;ba' -e '}' -e 's/.*@.*SOA[^0-9]*//;s/[^0-9].*//' \
   "$SOAfile")

此表单适用于单行和多行输入文件。

在应用替换之前,首先将多行输入文件作为整体读取。

注意:需要使用尴尬的单独-e选项来保持FreeBSD对标签和分支命令的满意,这需要文字\n进行终止 - 使用单独的-e选项是使用$'\n'在文字换行符中拼接的更具可读性的替代方法。


替代解决方案,使用awk

SOA=$(awk -v RS='@' '$1 == "IN" && $2 == "SOA" { print $6 }' "$SOAfile")

同样,这将适用于单行和多行记录定义。

唯一的限制是注释不得在序列号之前。

此外,如果文件包含多个记录,则上述内容将收集所有序列号,每个序列号用换行符分隔。

答案 2 :(得分:0)

为什么sed?在这种情况下,grep最简单:

grep -A1 -e '@.*SOA' 1 | grep -oe '[0-9]*'

或:(也许更好):

grep -A1 -e '@.*SOA' 1 | grep 'Serial number' | grep -oe '[0-9]*'

答案 3 :(得分:0)

这可能适合你(GNU sed):

sed -nr '/@ IN SOA/{/[0-9]/!N;s/[^0-9]+([0-9]+).*/\1/p}' file

对于包含@ IN SOA的行,如果该行不包含数字,则追加下一行。然后从线中提取第一个数字序列。