繰り返し、複数の構成に現れるパラメーター(例えば、インターフェースのIPアドレス)を変更する必要がある場合に対処する必要がありました。 また、推測するのが論理的であるため、どのようなファイルが「すぐに」思い出すことは困難であることが判明しました。
このアイデアは新しいものではなく、テンプレートの使用に基づいています。 言語はルビーです。
初期構成ファイルのタイプとしてXMLを選択することにしましたが、これは非常に適しています。 YAMLなどに目を向けることができます。
<xml> <構成名= 'rc.conf'> <インターフェース> <iface name = 're0' tag = 'internal'> <ip> 172.16.0.1 </ ip> <netmask> 255.255.255.240 </ netmask> <media> 1000baseTX </ media> <mediaopt>全二重</ mediaopt> <opts>ポーリング</ opts> </ iface> <iface name = 're1' tag = 'external'> <ip> 172.16.0.17 </ ip> <netmask> 255.255.255.228 </ netmask> </ iface> <iface name = 'fxp0'> <dhcp> true </ dhcp> <opts>ポーリング</ opts> </ iface> <エイリアスiface = 're0' num = '0'> <ip> 10.0.0.1 </ ip> <netmask> 255.255.255.0 </ netmask> </エイリアス> <クローン> vlan101 vlan110 vlan111 </ cloned> </ interfaces> </ config> </ xml>
LibXMLを使用してより速く解析し、それを選択しました。 類似として、 REXML、またはXMLファイルからハッシュを作成するXmlSimpleの既製の代替手段を検討できますが、より遅くなります。この点については以下で説明します。
テンプレートでの作業には、 erubisを選択しました 。
テストによると、 ERBやerubyよりも速いようです 。
実際にはコード自体:
「rubygems」が必要 「エルビス」が必要 「xml」が必要 def xml2hash(xml = nil) xml.nilの場合、「missed 'xml' param」を発生しますか? v = []; h = {} ループする xml.read break if(xml.node_type == XML :: Reader :: TYPE_END_ELEMENT || xml.empty_element?) if(xml.node_type == XML :: Reader :: TYPE_ELEMENT) 名前= xml.name h [名前] || = [] attrib = {} if(xml.attribute_count> 0)then カウント= xml.attribute_count while(count> 0)do カウント-= 1 xml.move_to_attribute(カウント) attrib.merge!({xml.name => xml.value}) 終わり 終わり r = xml2hash(xml) ケースr ハッシュするとき r.merge!(attrib)attrib.emptyでない限り? h [名前] .push(r) とき配列 h [name] .push(attrib)attrib.emptyでない限り? h [名前] .push(* r) 他に h [name] .push(attrib)attrib.emptyでない限り? h [名前] .push(r) r.nilでない限り終了しますか? elsif(xml.node_type == XML :: Reader :: TYPE_TEXT &&!xml.value.nil?) xml.value.split( "\ n")。各{| i | i.gsub!(/ ^ \ s *?(\ S +)\ s * $ /、 '\ 1'); v.push(i)except(i.empty?|| i =〜/ ^ \ s * $ /); } 終わり 終わり r = [] r.push(h)(h.nil?|| h.empty?)でない限り r.push(* v)(v.nil?|| v.empty?)以外 リターン* r レスキュー=> e puts "#{e.class}:#{e}(method:xml2hash)" 終わり 始める xml = XML :: Reader.file( 'params.xml') r = xml2hash(xml) xml.close r ['xml']。最初の['config']。各do | i | テンプレート= File.read(i ['name'] + ".eruby") eruby = Erubis :: Eruby.new(テンプレート) File.open(i ['name']、 "w"){| file | file.puts eruby.evaluate({:list => i})} 終わり レスキュー=> e puts "#{e.class}:#{e}(method:main)" 終わり
コードの詳細は説明しません。xml2hashメソッドの再帰呼び出しが使用されているとだけ言います。ブロックの始まりであれば、さらに深く、ブロックの終わりまたは空の要素/ブロックであれば、上に戻ります。
テンプレートファイルはxml + '.eruby'のconfig_nameです。 私の場合、rc.conf.eruby。
出力はconfig_name(rc.conf)にあります。
テンプレートコンテンツ:
<% for item in @list['interfaces'].first['iface'] %>
ifconfig_<%= item['name'] %>="<% unless item['dhcp'] %>inet <%= item['ip'].first %> netmask <%= item['netmask'].first %><% else %>DHCP<% end %><% unless (item['media'].nil? || item['media'].empty?) %> media <%= item['media'].first %><% end %><% unless (item['mediaopt'].nil? || item['mediaopt'].empty?) %> mediaopt <%= item['mediaopt'].first %><% end %><% unless (item['opts'].nil? || item['opts'].empty?) %> <%= item['opts'].first %><% end %>"
<% end %>
<% for item in @list['interfaces'].first['alias'] %>
ifconfig_<%= item['iface'] %>_alias<%= item['num'] %>="inet <%= item['ip'].first %> netmask <%= item['netmask'].first %>"
<% end %>
<% if @list['interfaces'].first.key?('cloned') && !@list['interfaces'].first['cloned'].empty? %>cloned_interfaces="<%= @list['interfaces'].first['cloned'].join(' ') %>"<% end %>
はい、それはやや読めないように見えますが、これは一見しただけです:)
約束どおり、「上記のコード」とXmlSimpleのテストに移りましょう。
xml_test.rb:
「rubygems」が必要 「xml」が必要 「ベンチマーク」が必要 def xml2hash(xml = nil) #メソッド定義上記参照 終わり 始める xml = '' Benchmark.bm do | x | x.report {100.times do xml_read = XML :: Reader.file( 'params.xml') xml = xml2hash(xml_read) xml_read.close 終了} 終わり p xml レスキュー=> e puts "#{e.class}:#{e}(method:main)" 終わり
ezhik @ pollux:〜$ time ruby xml_test.rb ユーザーシステムの総実数 0.210000 0.010000 0.220000(0.253391) {"xml" => [{"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0 "]、" num "=>" 0 "、" ip "=> [" 10.0.0.1 "]、" iface "=>" re0 "}]、" iface "=> [{" name "=>" re0 "、" netmask "=> [" 255.255.255.240 "]、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア"=> [" 1000baseTX "]、" ip "=> [" 172.16.0.1 "]}、{" name "=>" re1 "、" netmask "=> [" 255.255.255.228 "]、" tag "= > "external"、 "ip" => ["172.16.0.17"]}、{"name" => "fxp0"、 "opts" => ["polling"]、 "dhcp" => ["true"] }]、 "クローン" => ["vlan101"、 "vlan110"、 "vlan111"]}]}}}}]}} 実数0m0.447s ユーザー0m0.344s sys 0m0.036s
xml_simple.rb:
「rubygems」が必要 「xmlsimple」が必要 「ベンチマーク」が必要 xml = '' Benchmark.bm do | x | x.report {100.times do xml = XmlSimple.xml_in( 'params.xml') 終了} 終わり p xml
ezhik @ pollux:〜$ time ruby xml_simple.rb ユーザーシステムの総実数 1.770000 0.100000 1.870000(1.956282) {"config" => [{"name" => "rc.conf"、 "interfaces" => [{"alias" => [{"netmask" => ["255.255.255.0"]、 "num" = > "0"、 "ip" => ["10.0.0.1"]、 "iface" => "re0"}]、 "iface" => [{"netmask" => ["255.255.255.240"]、 " name "=>" re0 "、" opts "=> [" polling "]、" tag "=>" internal "、" mediaopt "=> ["全二重 "]、"メディア "=> [" 1000baseTX " ]、 "ip" => ["172.16.0.1"]}、{"netmask" => ["255.255.255.228"]、 "name" => "re1"、 "tag" => "external"、 "ip "=> [" 172.16.0.17 "]}、{" name "=>" fxp0 "、" opts "=> [" polling "]、" dhcp "=> [" true "]}]、" clone "= > ["\ n vlan101 \ n vlan110 \ n vlan111 \ n"]}]}]}} 実際の0m2.279s ユーザー0m2.012s sys 0m0.124s
はい、それはまさにxmlを解析した後のハッシュの外観です。
時間差はありますが、このタスクにはそれほど重要ではないと思うので、選択はあなた次第です。
その結果、私は得た:
ifconfig_re0 = "inet 172.16.0.1ネットマスク255.255.255.240メディア1000baseTX mediaopt全二重ポーリング" ifconfig_re1 = "inet 172.16.0.17 netmask 255.255.255.228" ifconfig_fxp0 = "DHCPポーリング" ifconfig_re0_alias0 = "inet 10.0.0.1 netmask 255.255.255.0" clone_interfaces = "vlan101 vlan110 vlan111"
終わり。