ユニケージ開発手法は上から下へ読めることを基本としている。このため、while構文やfor構文は極力使わない。回数が少なければループ展開するし、ユニケージ開発手法的な記述ができるならそちらを使うことが多い※1。
たとえば、九九の2の段を表示したいとする。手続き型プログラミング言語的な発想でシェルスクリプトを書くと、次のようになる。
for i in 1 2 3 4 5 6 7 8 9; do echo "2×${i}=$((2 * ${i}))" done
ユニケージ開発手法では次のように記述する。
echo "2×1=$((2 * 1))" echo "2×2=$((2 * 2))" echo "2×3=$((2 * 3))" echo "2×4=$((2 * 4))" echo "2×5=$((2 * 5))" echo "2×6=$((2 * 6))" echo "2×7=$((2 * 7))" echo "2×8=$((2 * 8))" echo "2×9=$((2 * 9))"
ユニケージ開発手法では上から下に読めるというメンテナンス性を強く意識している。プログラミングに慣れていない現場の作業員は、繰り返し構文がでてくると理解が及ばないことがある。
似たような例を考えてみよう。ファイルa1.txt〜a10.txtは削除、b1.txt〜b10.txtは大文字にリネーム、c1.txt〜c10.txtは新規作成という処理は、手続き型プログラミング言語的な発想で記述すれば次のようになる。
for i in 1 2 3 4 5 6 7 8 9 10; do rm a${i}.txt mv b${i}.txt B${i}.TXT touch c${i}.txt done
ユニケージ開発手法の発想で記述すると次のようになる。
rm a1.txt ; mv b1.txt B1.TXT ; touch c1.txt rm a2.txt ; mv b2.txt B2.TXT ; touch c2.txt rm a3.txt ; mv b3.txt B3.TXT ; touch c3.txt rm a4.txt ; mv b4.txt B4.TXT ; touch c4.txt rm a5.txt ; mv b5.txt B5.TXT ; touch c5.txt rm a6.txt ; mv b6.txt B6.TXT ; touch c6.txt rm a7.txt ; mv b7.txt B7.TXT ; touch c7.txt rm a8.txt ; mv b8.txt B8.TXT ; touch c8.txt rm a9.txt ; mv b9.txt B9.TXT ; touch c9.txt rm a10.txt; mv b10.txt B10.TXT; touch c10.txt
ただし、すべてのケースでループ展開すればよいというものではない。ユニケージ開発手法では展開したスクリプトがテキストエディアの1画面に収まるかどうかを、ループ展開するかどうかのひとつの判断基準にしている。1画面に収まらないようなループ展開は、逆に読みにくくなる。
なお、先ほどの例であれば、次のようにbashやzshのブレース展開を使用するという方法もある。
rm a{1,2,3,4,5,6,7,8,9,10}.txt rename b B b{1,2,3,4,5,6,7,8,9,10}.txt touch c{1,2,3,4,5,6,7,8,9,10}.txt
繰り返し構文を使わなければ記述できない場合には、繰り返しの終了判断をループの最後に記述する。通常、whileは次のように最初に繰り返し終了判定を記述することが多い。
i=1 while [ $i -le 10 ]; do # 10または10よりも小さければループ継続 echo "${i}周目" i=$(( $i + 1 )) done
ユニケージ開発手法では次のように終了判定を繰り返し構文の一番最後に書く。
i=1 while [ 1 ]; do echo "${i}周目" i=$(( $i + 1 )) [ $i -gt 10 ] && break; # 10よりも大きければループ終了 done
繰り返しの終了判定はループの先頭に記述されているよりも、ループの最後に記述されている方が直感的のようだ。プログラミングに慣れた方は先頭に条件文を書くことになんの疑問も抱かないが、業務システムを作ることになる現場の担当者は、先頭に条件を書くという書き方にひどく違和感を覚える方が多い。
xargs(1)コマンドを使うことで、繰り返し構文を平易なパイプラインに置き換えることができる。たとえば標準出力にスペース区切りで0000.txt 0001.txt 0002.txt (略) 9999.txtという文字列が送られたとする※2。シェルには処理できる引数の個数や文字列長に限界があるため、そのままパイプラインに流すと処理に失敗することがある。
ここで"| xargs touch"のようにxargs(1)コマンドを経由して受けるというにすると、touch(1)コマンドに渡す引数の数を調整して処理を実施してくれるようになる。この特性を利用すると、繰り返し構文を平易なパイプラインに置き換えることができる。
たとえば、パスの中にBACKUPという文字列が含まれているものを除いて、いくつかのディレクトリをtar(1)でBACKUP.tarにアーカイブするケースを考える。ユニケージ開発手法の発想をしないのであれば、次のような書き方をするだろう。
for file in */AJAX/* */CGI/* */HTML/* */IMG/*; do if [ 0 -ne $(expr $file : BACKUP) ]; then tar -rpf BACKUP.tar $file fi done
ユニケージ開発手法の発想で書くと次のようになる。
echo */AJAX/* */CGI/* */HTML/* */IMG/* | tarr | sed '/BACKUP/d' | xargs tar -rpf BACKUP.tar
繰り返し構文も分岐構文も使わずに、平易なパイプラインになっている。このように上から下へそのまま読めるようにすることが、ユニケージ開発手法のひとつの作法である。
※1 繰り返し構文を使用しないシェルプログラミングはシェルプログラミングTips : 制御構文whileやforを避ける方法も参照のこと。
※2 フィールド形式も参照のこと。
※ ユニケージはユニバーサル・シェル・プログラミング研究所の登録商標。
※ usp Tukubaiはユニバーサル・シェル・プログラミング研究所の登録商標。
※ 本ページで公開されているプログラムとそれに付随するデータの著作権およびライセンスは、特に断りがない限りOpen usp Tukubai本体と同じMITライセンスに準拠するものとする。
USP MAGAZINE Vol.3「第一回 ユニケージエンジニアの作法」より加筆修正後転載。