Bourne Shellで日付チェックするシェルを作成

エスキモーの「きなこもち風もなか」が美味いよ、bonlifeです。今後、Windowsでもコマンドラインツールが拡張されるようですね。MSH(コード名:Monad)ですって。(紹介記事はこちら。)ということで、日付チェックシェル、今度はいわゆるシェル(Bourne Shell)で作ってみました。リダイレクトまわりが間違っているかもしれませんが、まぁ気にしない、ということで。(rmコマンドの結果のリダイレクトを行っているのですが、正常終了の場合は出力がないはずなので、エラーだけ/dev/nullに放り込めば良いかな、と思ったのですがどうなんでしょう。)引数は以前と同様にYYYYMMDD形式しか想定していません。必要に応じてカスタマイズしてみてくださいませ。
他のシェルで同じ機能を実装したものは、以下のリンク先にてご確認いただけます。

(2006/07/19) 豪快に間違えている部分があったので、書き直しました。ついでにbashでの経験を活かし、中間ファイルを作成しないようにしました。

checkdate

#! /bin/sh

# usage : checkdate YYYYMMDD

# エラー処理用関数定義

error_exit () {
  rm -f *_$$.dat 2> /dev/null
  exit 1
}

# 引数の数をチェック
# 引数が1つでない場合、エラー終了
# エラー終了時は error_exit を呼び出す

if [ $# -ne 1 ]
then
  error_exit
fi

# 桁数チェック
# 8桁でない場合、エラー終了
#
# echo $1 > input_value_$$.dat
# if [ `awk '{print length($1)}' input_value_$$.dat` -ne 8 ]
# then
#   error_exit
# fi

if [ `expr length $1` -ne 8 ]
then
  error_exit
fi

# 値の妥当性チェック (簡易チェック)
#
# echo $1 | egrep '^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$' > tmp_date_$$.dat
# if [ -z tmp_date_$$.dat ]
# then
#   error_exit
#fi

# 上記の簡易チェックは機能しないので、改訂

if ! [ `echo $1 | egrep '^[0-9]{4}(0[1-9]|1[0-2])(0[1-9]|[1-2][0-9]|3[0-1])$'` ]
then
  error_exit
fi

# 入力値を分割して変数にセット
# 月、日については先頭の 0 を削除しておく
# 0 を削除しておくのは、数値の大小比較などで使うため
#
# cshベースで考えていた一時ファイルを作成する方法を変更
#
# YEAR=`cut -c1-4 input_value_$$.dat`

YEAR=`expr substr $1 1 4`

# if [ `cut -c5-5 input_value_$$.dat` -eq 0 ]
# then
#   MONTH=`cut -c6-6 input_value_$$.dat`
# else
#   MONTH=`cut -c5-6 input_value_$$.dat`
# fi

if [ `expr substr $1 5 1` -eq 0 ]
then
  MONTH=`expr substr $1 6 1`
else
  MONTH=`expr substr $1 5 2`
fi

# if [ `cut -c7-7 input_value_$$.dat` -eq 0 ]
# then
#   DAY=`cut -c8-8 input_value_$$.dat`
# else
#   DAY=`cut -c7-8 input_value_$$.dat`
# fi

if [ `expr substr $1 7 1` -eq 0 ]
then
  DAY=`expr substr $1 8 1`
else
  DAY=`expr substr $1 7 2`
fi

# 日のチェック ( 詳細 : 月ごとの最終日と閏年の考慮 )

ENDDAY1=31
ENDDAY2=28
ENDDAY3=31
ENDDAY4=30
ENDDAY5=31
ENDDAY6=30
ENDDAY7=31
ENDDAY8=31
ENDDAY9=30
ENDDAY10=31
ENDDAY11=30
ENDDAY12=31

eval LASTDAY=\$ENDDAY$MONTH

if [ $MONTH -eq 2 -a `expr $YEAR % 4` -eq 0 -a `expr $YEAR % 100` -ne 0 ]
then
    LASTDAY=`expr $LASTDAY + 1`
elif [ $MONTH -eq 2 -a `expr $YEAR % 400` -eq 0 ]
then
    LASTDAY=`expr $LASTDAY + 1`
fi

if [ $DAY -gt $LASTDAY ]
then
  error_exit
fi

# 上記全てのチェックで問題がなければ戻り値 0 で終了

rm -f *_$$.dat > /dev/null
exit

Bourne Shellも慣れれば使いやすそうですね。リダイレクトの記号と比較の記号が異なるのも、最初は違和感がありましたが、この方が間違いが少ない気がします。また、cshでは関数を使うことができなかったのでエラー時の処理にラベルを付与してgotoで移動させていましたが、Bourne Shellでは関数が使えるので少しソースがキレイになったような気がします。めでたし、めでたし。と言いたいところなのですが、ソース見ていただけば分かるように月の最終日の設定をちょっとトリッキーなやり方で実装してます。なんとBourne Shellでは配列が使えないのです!ガビョーン。というわけで、Bourne Shell で配列もどきを実装する方法を参考にさせていただき、配列っぽい動きをさせることにしました。
次は関数も配列も使えるkshだっ!(本当はbashあたり試してみたいのですが、Linux環境がないんですよね…。KNOPPIXあたりから始めてみようかしら。)