2011年2月28日月曜日

Rubyの例外処理の落とし穴

(わたしの中では)使用頻度が低い Ruby を使ってスクリプトを書いていて、例外処理で初歩的な間違いを起こしましたので、メモしておきます。
begin
        ...
rescue  Errno::EPIPE => e
        ...
ensue
        temp.close(true)
end
とても初歩的なミスなのですが、ensure と書くべきところを ensue と間違って入力したために、必ず削除されるつもりの一時ファイルが残るというバグでした。このように間違えると、ensue は、rescue 節の一部と解釈されるので、rescue 節が走行する場合にしか、エラーにはなりません。

2011年2月13日日曜日

getoptによるロングオプション解析

ロングオプション(--tmpdir /tmp みたいなやつ)が欲しいと思ったことはなかったのですが、この日書いていたスクリプトに、意味をよく理解して注意して指定して欲しいオプションを実装しようとしていて、そういう局面ではロングオプションを使うのがいいのでは?と思い至りました。
そこで、まずは練習として、前に書いたテンプレート(getoptを使う版)を拡張して、ロングオプションに対応してみました。
#!/bin/bash
#
# getopt-long-template.bash (use getopt utility)
#
export LANG=C
usage_exit() {
        echo "Usage: getopt-long-template.bash [-a] [-d dir] [--extra] [--file f] item1 item2 ..." 1>&2
        exit 1
}
#
# Options
#
echo "$@"       ####DEBUG
GETOPT=`getopt -q -o ad:h -l extra,file: -- "$@"` ; [ $? != 0 ] && usage_exit
eval set -- "$GETOPT"
echo "$@"       ####DEBUG
while true
do
  case $1 in
  -a)   A_FLAG=yes      ; shift
        ;;
  -d)   OUTDIR=$2       ; shift 2
        ;;
  --extra)      EXTRA_F=yes     ; shift
        ;;
  --file)       OUTFILE=$2      ; shift 2
        ;;
  -h)   usage_exit
        ;;
  --)   shift ; break
        ;;
  *)    usage_exit
        ;;
  esac
done
#
echo \$#=$#             ####DEBUG
echo \$@="$@"           ####DEBUG
echo A_FLAG=$A_FLAG     ####DEBUG
echo OUTDIR=$OUTDIR     ####DEBUG
echo EXTRA_F=$EXTRA_F   ####DEBUG
echo OUTFILE=$OUTFILE   ####DEBUG
実行結果は次のとおりです。--extra オプションと --file f オプションを解釈できるようになりました。
# ./getopt-long-template.bash item1 item2 -d dir --extra --file f
item1 item2 -d dir --extra --file f
-d dir --extra --file f -- item1 item2
$#=2
$@=item1 item2
A_FLAG=
OUTDIR=dir
EXTRA_F=yes
OUTFILE=f

下記も参照ください。
オプション解析(getoptsとgetoptの使い分け)

2011年2月9日水曜日

Rubyには++演算子が無いと気づきました

(わたしの中では)使用頻度が低い Ruby を使ってスクリプトを書いていたら、++演算子が無いことに気がつきました。
                        ...
     53                 try_count = 0
     54                 begin
     55                         try_count++
     56                         gz = Zlib::GzipReader.wrap(workf)
     57                 rescue  Zlib::GzipFile::Error => e
     58                         if try_count < 3
     59                                 retry
     60                         else
     61                                 STDERR.puts "WARNING: "+e.message
     62                         end
     63                 ensure
                        ...
上のようなコード(gzip圧縮ファイルを直接扱う処理)を書いていたのですが、これを実行すると次のようなエラーになり、
xxx.rb:56: undefined method `+@' for #<Zlib::GzipReader:0x7f134cbb98b8> (NoMethodError)
56行目を間違っている??と思って、なんのこっちゃとアタフタすること1時間くらい。。。 もしかして++がいけないのかなと、try_count +=1 にしたらエラーが出なくなりました。 Ruby には、++ないんだねー! 知りませんでした。

2011-03-15追記
なぜなのかについては、下記を参照。
http://okwave.jp/qa/q4634346.html
人気ブログランキングへ にほんブログ村 IT技術ブログへ