コマンドの処理が一定時間以上かかった時だけGrowlで通知する

~/.bashrcに書いておけば多分動く。bash以外で動くかは試してない。
Mac用に書いてるのでLinuxとかは適宜コマンドを(notify-sendとかに)置き換えてください。

function notify-last-command {
  # 3秒以上かかったらGrowlで通知する
  if [ 3 -lt $MYDATETIME ]; then
    growlnotify -n notify-last-command -t command -m "$( history 1 | awk '{s="";for(i=2;i<=NF;i++){s=s" "$i}print s}' )"
  fi

  MYDATETIME=0
}

PROMPT_COMMAND='notify-last-command'

MYDATETIME=0

function time_spent () {
  MYDATETIME=$(expr $(date +%s) - $MYDATETIME)
}
trap 'time_spent' DEBUG

仕組み

BashのPROMPT_COMMANDとtrapを利用している。
PROMPT_COMMANDに値を指定すると、プロンプトが表示される直前に指定した値がコマンドとして実行される。*1
trapは、本来はシグナルをトラップして色々処理するためのものらしいんだけど、上記のようにDEBUGを指定するとコマンドを入力してエンターを押した直後とPROMPT_COMMANDの直前で実行されるようなので今回はそれを利用している。*2
動作の順番としては、以下のようになっている。

  1. コマンドを打ってエンターを押す
  2. 1回目のtrapが動き、MYDATETIMEに今の時間をUNIX timeに変換したものが入る
  3. コマンド本体の処理が行われる
  4. 2回目のtrapが動き、MYDATETIMEに今の時間をUNIX timeに変換したものから元のMYDATETIME分引いたもの(つまりコマンドの実行にかかった時間)が入る
  5. PROMPT_COMMANDが動き、MYDATETIMEの値が3以上であればgrowlnotifyが起動する

作った理由

MacPortsのアップデートのような時間がかかる処理を終わったかどうかいちいちチェックするの面倒だし終わったら通知してほしい、みたいな感じです。

思うこと

このままだと

  • vimでファイルを編集して閉じる時
  • 新規にタブやウィンドウ作った時
  • topやman等からプロンプトに戻った時
  • パイプを使った時
  • 単にエンターキーを押した時

等にGrowlされてしまうのでその辺うまく解決出来ないかな〜と思う。

*1: 詳細はman bash(1)

*2: 詳細はhelp trap