2014-04-22 20 views
2

我將多個域的SOA數據存儲在單個文件中,該文件按區域文件獲取$INCLUDE d。我編寫了一個小的sed腳本,該腳本應該可以獲得序列號,然後重新保存SOA文件。只要SOA文件格式正確,整個記錄在一行上就可以正常工作,但只要記錄分成多行,它就會失敗。如何從sed文件中獲取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 

喜歡的意見,我想傳播的事情了。但我需要我的腳本能夠找到序列號,以便我可以增加它並重寫該文件。上單線工作

戰略經濟對話是這樣的:

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

但對於多行...我有點失落。我知道我可以連線N,但我怎麼知道我是否需要需要?我是否需要根據原始文件的其他分析來編寫單獨的sed腳本?

請幫忙! :-)

+0

你必須使用sed嗎?還是會用其他工具呢? – ghoti

+0

我對其他工具很開放,但是我在FreeBSD上,所以我寧願不使用那些需要安裝基本操作系統所沒有的東西。這排除了Perl,Python,紅寶石等。 – Graham

回答

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。它還根據您的區段是否包含可選的「IN」關鍵字來調整字段編號。

一個純sed的解決辦法,而不是計算領域,用數字的第一串開括號後您的/^@/後,像這樣:

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記錄上。

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") 

再次,這將與的單人和多行記錄定義工作。

唯一的限制是註釋不能在序列號之前。

此外,如果一個文件包含多個記錄,上述將收集所有序列號,每個序號由一個換行符分隔。

0

爲什麼sedgrep是簡單的在這種情況下:

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

或(也許更好):

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

感謝您的回答。如果我可以依靠下一行('-A1')上的序列號,那將會很好,但如果文件是雙倍間隔的呢?或者在括號內的部分有其他註釋行?或沒有「序列號」之類的評論?我希望能夠匹配BIND理解的任何區域文件,而不僅僅是我期望的約定。 – Graham

0

這可能會爲你工作(GNU SED):

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

對於包含@ IN SOA線如果該行不包含數字,則附加下一行。然後從行中提取第一個數字序列。