UECジャーナル

ユニケージエンジニアの作法その一 forやwhileなどの繰り返し構文の使用は控える

ユニケージ開発手法は上から下へ読めることを基本としている。このため、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画面に収まらないようなループ展開は、逆に読みにくくなる。

なお、先ほどの例であれば、次のようにbashzshのブレース展開を使用するという方法もある。

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)コマンドで繰り返しと同様の効果

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「第一回 ユニケージエンジニアの作法」より加筆修正後転載。

Last modified: 2014-01-13 00:00:00