前回の記事では、bashシェルの機能を拡張するBashDiffというパッチについて紹介した。BashDiffの適用によりbashで利用可能となるコマンドや文字列の構文解析については、先に解説したとおりである。今回はその続きとして、位置パラメータの操作法、XMLの構文解析、ISAMやリレーショナルデータベースとの通信、GTK+2 GUIの作成、その他若干のテクニックや注意事項を紹介することにする。
位置パラメータの操作
BashDiffから提供される位置パラメータの操作用コマンドは、多くの場合、ノーマル状態のbashよりもかなり効率的な処理を可能にしてくれる。例えばその1つであるpcursorは、複数の位置パラメータにおける現在値を1つのグループにまとめて取り扱えるようにし、これらのクリアおよび、スタックへの待避や取り出しを一括して扱うためのコマンドだ。位置パラメータそのものを操作するその他の追加コマンド群には、pp_というプレフィックスが付けられている。またオプション扱いではあるが、これらのコマンドでは-aパラメータを指定することで、明示的な名前を付けた配列にて位置パラメータを格納させることも可能だ。例えば下記のサンプルは、ノーマル状態およびBashDiff適用後のbashにおける位置パラメータの追加コマンドを比較したものである(後者が下側)。
$ set -- $@ Z $ pp_append Z
実際、pp_系コマンドの多くは、ノーマル版bashシェルでの操作よりも処理速度が大幅に向上している。もっとも、pp_プレフィックスの付いたコマンド群がどの程度有用かは、個々のユーザにおける位置パラメータの使用頻度で決まるものであるが、その効果は特にループ処理にて顕著に現れることになるだろう。例えば下記のサンプルコードはその極端な実装例で、負荷の大きいプリペンド操作を1つのループ中で1,000回実行させている。この実行結果を見ると、pp_バージョンのコードの方が非常に効率的な処理となっていることが分かるだろう。ただしループ回数を100に下げた場合、ノーマル版bashコマンドでも0.15秒で終了している。確かにこの場合においてもBashDiff版の方が所要時間0.006秒という点で高速ではあるが、こうした位置パラメータ操作の100回ループが他のスクリプトから何度も呼び出されるのでなければ、ノーマル版bashの処理であっても許容範囲内と見なせるかもしれない。
$ pp_trim 10000 $ time for i in `seq 1 1000`; do set -- Zoldpre $@; done real 0m10.157s user 0m9.880s sys 0m0.004s $ pp_trim 10000 $ time for i in `seq 1 1000`; do pp_push Zoldpre; done real 0m0.088s user 0m0.036s sys 0m0.002s
XMLファイルのパース
次にBashDiffでサポートされる、ExpatというXMLパーサについて見てみよう。このexpatビルトインの呼び出しで処理できるのは、1度に1つのXMLファイルだけだが、XMLの処理中はその中に含まれる、エレメント、コメント、名前空間などが検出されるごとに、指定した1群のコールバックが呼び出されていく。そしてBashDiffは、いくつかのハウスキーピング作業をユーザの代わりに自動で処理してくれる。例えば、XML_TAG_STACK配列にはXMLの全エレメントの名前が格納されるので、カレントのエレメントを特定することに利用できるし(コールバック時)、XML_ELEMENT_DEPTHを調べればカレントXMLエレメントの階層を確認できるのだ。なおXML属性は、各属性別の明示的なコールバックで個別処理をするのではなく、すべての属性がパラメータ群に渡された上で、XMLエレメントのコールバックが開始されるようになっている。
Expatコールバックのエントリポイントとしては、bashの関数群を利用するのが便利だろう。下記のサンプルコードは、ugu.xmlという簡単な構成のファイルを、BashDiffのexpatビルトインを用いて構文解析させるというものだ。ここでのstartelem関数の役割は、新規XMLエレメントの処理開始を行うことで、ノーマル版bashのdeclare関数を用いて、呼び出し時におけるXML_TAG_STACK配列の内容を表示させている。そしてこのサンプルコードでは、XML属性がどのように処理されているかを示すため、BashDiffによりstartelemに渡される2つ目のパラメータを出力させるようにしている。
$ cat ugu.xml
<ugu foo="bar" linux="fun">
<nested one="two" three="four" />
</ugu>
$ startelem() {
declare -p XML_TAG_STACK;
echo $2;
}
$ expat -s startelem ugu.xml
declare -a XML_TAG_STACK='([0]="ugu")'
foo=bar
declare -a XML_TAG_STACK='([0]="nested" [1]="ugu")'
one=two
