search
LoginSignup
25

More than 5 years have passed since last update.

posted at

zsh で 例外処理

zsh はプログラム言語で言うところの try/catch のような例外処理ができるので紹介する。

シンプルな例

書き方はこんな感じ。

#!/bin/zsh

autoload -Uz catch
autoload -Uz throw

{
  echo hoge
  throw 'MyException'
  echo fuga
} always {
  if catch 'MyException'; then
    echo "catch MyException!"
  fi
}

例外を投げるには throw、受け取るには catch という関数を使う。まずは両方とも autoload しておく。

例外処理をするときは全体を

{
  # try ブロック
  # ここにメイン処理を書く
} always {
  # always ブロック
  # 例外が発生した時もそうでない時も実行される
}

という形で書く。
always ブロックは例外が発生したかどうかにかかわらず常に実行されるので、この中で catch を使って例外が発生したかどうか判定すれば例外をキャッチできる。

この例を実行した結果はこんな感じ。

% ./exception_sample.zsh
hoge
catch MyException!

例外を投げた時点でうまく always ブロックに移行してるのが分かる。

複数の例外の種類を考慮する例

もうちょっと複雑な例を見てみる。

#!/bin/zsh

autoload -Uz catch
autoload -Uz throw

{
  lock_dir_name="lock_dir"

  mkdir $lock_dir_name || throw 'LockException'

  # メイン処理
  # ...

  rmdir "$lock_dir_name"
} always {
  if catch '*'; then
    case $CAUGHT in
      (LockException)
        echo "LockException"
        ;;
      (NetworkException)
        echo "NetworkException"
        ;;
      (*)
        echo "other Exception"
        ;;
    esac
  fi

  # 後処理が必要ならここに書く
  # 例外が発生するかどうかにかかわらず実行される
  # 他の言語で言う finally に相当する

  echo "tear down"
}

このスクリプトでは、ディレクトリを作って排他制御をしてる。ロックの取得に失敗したときはすぐに例外を投げてメイン処理を行わないようになってる。

この例のように catch の引数はワイルドカードが使えるので、catch '*' とすればどんな名前の例外でもキャッチできる。どんな例外もキャッチして、例外の種類ごとに違うことをしたい場合はこんなふうに書くとうまくいく。

その他詳しいことは man zshcontrib の EXCEPTION HANDLING や man zshmisc の COMPLEX COMMANDS の { try-list } always { always-list } を参照。

こんな感じで例外処理を使うとエラー処理がシンプルに書けるようになるので、ぜひ試してみてください!

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
25