シェルスクリプトはCGIとしても活用できる。ここではその基本として、次のようなスクリプトからはじめて、データファイルから表およびグラフを出力するHTMLを作成する。
#!/bin/sh cat << EOF > ./out.html <!DOCTYPE html> <html> <head><meta charset="UTF-8" /></head> <body> $(date) </body> </html> EOF
HTML文書の出力にはヒアドキュメントを使っている。cat << EOFがヒアドキュメントのはじまりだ。ここからEOFまでが> ./out.htmlの指定にしたがってout.htmlファイルに出力される。ヒアドキュメントの途中に$(date)というコマンド置換の指定があるため、この部分はdate(1)の実行結果に置き換わることになる。
ここに表を追加する。表の元となるデータは次のようなフィールド形式のファイルとする。ファイル名はHOMERとする。通算本塁打数をまとめたファイルだ。
順位 選手 本塁打 FROM TO 試合 打数 1 王 貞治 868 1959 1980 2831 9250 2 野村 克也 657 1954 1980 3017 10472 3 門田 博光 567 1970 1992 2571 8868 4 山本 浩二 536 1969 1986 2284 8052
このデータを次のようなHTMLのtable要素に置き換えることを考える。
<table> <tr> <td>1行1列</td> <td>1行2列</td> </tr> <tr> <td>2行1列</td> <td>2行2列</td> </tr> </table>
どのように実装してもよいが、たとえば次のようにawk(1)を使う。
#!/bin/sh tmp=/tmp/$$ awk '{ print " <tr>"; for (i = 1; i <= NF; i++) { print " <td>" $i "</td>" }; print " </tr>" }' ./HOMER > $tmp-table tee $tmp-html << EOF <!DOCTYPE html> <html> <head><meta charset="utf-8" /></head> <body> <h1 style="font-size:18px">通算本塁打</h1> <table border="1" cellspacing="0"> $(cat $tmp-table) </table> </body> </html> EOF rm -f $tmp-*
このシェルスクリプトを実行すると、次のようなHTMLファイルが出力される。
<!DOCTYPE html> <html> <head><meta charset="utf-8" /></head> <body> <h1 style="font-size:18px">通算本塁打</h1> <table border="1" cellspacing="0"> <tr> <td>順位</td> <td>選手</td> <td>本塁打</td> <td>FROM</td> <td>TO</td> <td>試合</td> <td>打数</td> </tr> <tr> <td>1</td> <td>王 貞治</td> <td>868</td> <td>1959</td> <td>1980</td> <td>2831</td> <td>9250</td> </tr> <tr> <td>2</td> <td>野村 克也</td> <td>657</td> <td>1954</td> <td>1980</td> <td>3017</td> <td>10472</td> </tr> <tr> <td>3</td> <td>門田 博光</td> <td>567</td> <td>1970</td> <td>1992</td> <td>2571</td> <td>8868</td> </tr> <tr> <td>4</td> <td>山本 浩二</td> <td>536</td> <td>1969</td> <td>1986</td> <td>2284</td> <td>8052</td> </tr> </table> </body> </html>
ブラウザでは次のようにレンダリングされる。
順位 | 選手 | 本塁打 | FROM | TO | 試合 | 打数 |
1 | 王 貞治 | 868 | 1959 | 1980 | 2831 | 9250 |
2 | 野村 克也 | 657 | 1954 | 1980 | 3017 | 10472 |
3 | 門田 博光 | 567 | 1970 | 1992 | 2571 | 8868 |
4 | 山本 浩二 | 536 | 1969 | 1986 | 2284 | 8052 |
最近のメジャーなブラウザはすべてSVGのレンダリング機能を備えているので、グラフの記述にはこのフォーマットを利用できる。たとえば次のようなHTMLで棒グラフを描画することができる。
<!DOCTYPE html> <html> <head><meta charset="UTF-8" /></head> <body> <svg style="height: 60px;> <text x="10" y="36" style="font-size:16px">USP</text> <rect x="50" y="20" width="300" height="20" fill="white" stroke="black" /> <text x="340" y="36" style="text-anchor:end">00</text> </svg> </body> </html>
ブラウザでレンダリングすると次のようになる。
ここではOpen usp Tukubaiのmojihame(1)を使って該当部分にデータをはめ込む処理を実施する。mojihame(1)は次のように指定されたテンプレートファイルにしたがってデータを出力するコマンド。
$ cat temp 長者番付(秘) AAA %1位 %2さん 納税額%3円 AAA $ cat data 1 松浦 12 2 濱田 8 3 上田 -5 4 法林 -110 $ mojihame -lAAA temp data 長者番付(秘) 1位 松浦さん 納税額12円 2位 濱田さん 納税額8円 3位 上田さん 納税額-5円 4位 法林さん 納税額-110円 $
たとえば次のようなシェルスクリプトでデータファイルから棒グラフを出力する処理になる。
#!/bin/sh -vx tmp=/tmp/$$ #1:順位 2:選手 3:本塁打 4:FROM 5:TO 6:試合 7:打数 #ヘッダを削る tail -n +2 ./HOMER | awk '{ wid = $3 / 2; print $2, $3, NR*24, NR * 24 + 16, wid + 95, wid }' > $tmp-data #1:選手名 2:本塁打数 3:グラフ左上y座標 4:字左下y座標 #5:本塁打数文字右端位置 6:グラフ幅 #テンプレートを準備 cat << EOF > $tmp-template <!DOCTYPE html> <html> <head><meta charset="UTF-8" /></head> <body> <svg style="height: 160px; font-size: 16px;"> <!-- RECORDS --> <text x="10" y="%4">%1</text> <rect x="100" y="%3" width="%6" height="20" fill="white" stroke="black" /> <text x="%5" y="%4" style="text-anchor:end">%2</text> <!-- RECORDS --> </svg> </body> </html> EOF #レコードをテンプレートに流し込む mojihame -lRECORDS $tmp-template $tmp-data > $tmp-html cp $tmp-html out.html rm -f $tmp-* exit 0
このシェルスクリプトを実行すると次のような出力が得られる。
<!DOCTYPE html> <html> <head><meta charset="UTF-8" /></head> <body> <svg style="height: 160px; font-size: 16px;"> <text x="10" y="40">王 貞治</text> <rect x="100" y="24" width="434" height="20" fill="white" stroke="black" /> <text x="529" y="40" style="text-anchor:end">868</text> <text x="10" y="64">野村 克也</text> <rect x="100" y="48" width="328.5" height="20" fill="white" stroke="black" /> <text x="423.5" y="64" style="text-anchor:end">657</text> <text x="10" y="88">門田 博光</text> <rect x="100" y="72" width="283.5" height="20" fill="white" stroke="black" /> <text x="378.5" y="88" style="text-anchor:end">567</text> <text x="10" y="112">山本 浩二</text> <rect x="100" y="96" width="268" height="20" fill="white" stroke="black" /> <text x="363" y="112" style="text-anchor:end">536</text> </svg> </body> </html>
ブラウザでのレンダリングは次のようになる。
このようにシェルスクリプトとコマンドのみでデータからグラフを含むHTMLを生成することができる。これはそのままCGIとして活用できるもので、たとえば本サイトはusp Tukubaiを使いシェルスクリプトベースのCGIが動作している。
「Keep it simple, stupid.※1」という言葉が表現しているように、極力シンプルな方法を採用することで、物事をうまく進めることができる。やりたいことをはっきりさせ、それに向けてフィールド形式のファイルやテンプレートファイルを用意する。あとはそれらを組み合わせることで処理を実現できる。複雑化せず、あくまでもシンプルな形式とやり方を保持することが大切だ。
※1 KISSの原則、Clarence "Kelly" Johnson.
Software Design 2012年4月号 上田隆一著、「テキストデータならお手のもの"開眼☆シェルスクリプト" : 【4】表とグラフを描く ― HTMLファイルの出力」より加筆修正後転載。
※ usp Tukubaiはユニバーサル・シェル・プログラミング研究所の登録商標。