2009/04/05

シェルスクリプト内でXMLから情報を取り出す

XML形式により情報をやり取りすることが多くなった昨今、シェルスクリプト(shell script)でXMLを扱うことも増えてきた。例えば、libvirtを使って
virsh dumpxml DomU名
として得た仮想マシンの設定情報などだ。Xen DomU dc1の設定ファイル/etc/xen/dc1が、
name = "dc1"
uuid = "4df3f764-00cb-42a6-8ff6-a98985cbda14"
maxmem = 256
memory = 64
vcpus = 1
bootloader = "/usr/bin/pygrub"
on_poweroff = "destroy"
on_reboot = "restart"
on_crash = "restart"
vfb = [ ]
disk = [ "phy:/dev/VolGroupXX/LogVolDc1,xvda,w" ]
vif = [ "mac=00:16:3e:ff:ab:01,bridge=br1000",
"mac=00:16:3e:ff:ab:02,bridge=br2000" ]
だったとしよう。このdc1の設定をXML形式で得ると、
# virsh dumpxml dc1
<domain type='xen' id='18'>
<name>dc1</name>
<uuid>094a82d5-7e6c-980d-49d3-9e8e68fb84e2</uuid>
<bootloader>/usr/bin/pygrub</bootloader>
<os>
<type>linux</type>
<kernel>/var/lib/xen/boot_kernel.rMNCqh</kernel>
<initrd>/var/lib/xen/boot_ramdisk.og2mn7</initrd>
<cmdline>ro root=/dev/VolGroup00/LogVol00 console=xvc0 acpi=off nopcmcia noapm nousb nofirewire nosound</cmdline>
</os>
<memory>262144</memory>
<currentMemory>65536</currentMemory>
<vcpu>1</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<interface type='bridge'>
<source bridge='br4000'/>
<target dev='vif18.0'/>
<mac address='00:16:3e:1d:89:01'/>
<script path='vif-bridge'/>
</interface>
<interface type='bridge'>
<source bridge='br2002'/>
<target dev='vif18.1'/>
<mac address='00:16:3e:1d:92:01'/>
<script path='vif-bridge'/>
</interface>
<disk type='block' device='disk'>
<driver name='phy'/>
<source dev='/dev/VolGroupXX/LogVolDc1'/>
<target dev='xvda'/>
</disk>
<console tty='/dev/pts/1'/>
</devices>
</domain>

#
のようになる。このとき、ディスクに関する情報を取り出したいとしよう。
まず、XML形式をファイルに保存する。
# virsh dumpxml dc1 > dc1.xml
#
このファイルを引数として、xmllintコマンドを対話モードで起動する。
# xmllint --shell dc1.xml
/ >
プロンプトの「/」は、現在のXML文書上のパスを示している。
ここで「cat」と入力すると、現在のパス以下の内容すべてが表示される。つまり、XMLファイルの内容すべてが表示されることになる。
/ > cat
<?xml version="1.0"?>
<domain type="xen" id="18">
<name>dc1</name>
<uuid>094a82d5-7e6c-980d-49d3-9e8e68fb84e2</uuid>
<bootloader>/usr/bin/pygrub</bootloader>
<os>
<type>linux</type>
<kernel>/var/lib/xen/boot_kernel.rMNCqh</kernel>
<initrd>/var/lib/xen/boot_ramdisk.og2mn7</initrd>
<cmdline>ro root=/dev/VolGroup00/LogVol00 console=xvc0 acpi=off nopcmcia noapm nousb nofirewire nosound</cmdline>
</os>
<memory>262144</memory>
<currentMemory>65536</currentMemory>
<vcpu>1</vcpu>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<interface type="bridge">
<source bridge="br4000"/>
<target dev="vif18.0"/>
<mac address="00:16:3e:1d:89:01"/>
<script path="vif-bridge"/>
</interface>
<interface type="bridge">
<source bridge="br2002"/>
<target dev="vif18.1"/>
<mac address="00:16:3e:1d:92:01"/>
<script path="vif-bridge"/>
</interface>
<disk type="block" device="disk">
<driver name="phy"/>
<source dev="/dev/VolGroupXX/LogVolDc1"/>
<target dev="xvda"/>
</disk>
<console tty="/dev/pts/1"/>
</devices>
</domain>

/ >
ただし、xmllintの出力は正規化されているため、先頭行が追加されている。
ディスクに関する設定は、XPath形式で表せば、「/domain/devices/disk」にあることが解る。これをcatで出力してみる。
/ > cat /domain/devices/disk
-------
<disk type="block" device="disk">
<driver name="phy"/>
<source dev="/dev/VolGroupXX/LogVolDc1"/>
<target dev="xvda"/>
</disk>
/ >
さらに、ソースデバイス名のみを抽出してみよう。
/ > cat /domain/devices/disk/source/@dev
-------
dev="/dev/VolGroupXX/LogVolDc1"
/ >
これを非対話的に実行するには、
# echo "cat /domain/devices/disk/source/@dev" | xmllint --shell dc1.xml
/ > -------
dev="/dev/VolGroupXX/LogVolDc1"
/ > #
とすればよい。
これと同様の操作をネットワークインターフェースに対して実行してみる。
# echo "cat /domain/devices/interface/source/@bridge" | xmllint --shell dc1.xml 
/ > -------
bridge="br4000"
-------
bridge="br2002"
/ > #
XPath /domain/devices/interfaceにマッチする要素は二つあるので、出力も二つだ。
これらのうち、二番目のものだけを出力するには、
# echo "cat /domain/devices/interface[2]/source/@bridge" | xmllint --shell dc1.xml
/ > -------
bridge="br2002"
/ > #
とする。

0 件のコメント: