我将多个域的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脚本?
请帮忙! : - )
答案 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
的行,如果该行不包含数字,则追加下一行。然后从线中提取第一个数字序列。