ターミナルで作業中、たまに意図せず時間のかかるコマンドを叩いてしまうことがあります。例えば、curlでダウンロード仕掛けたは良いけどファイルサイズが大きかったり、無意識にcarthage update
叩いてしまった場合などです。
そうなると、終わるまでちょっと待つかと思ってブラウザを開き、その結果ネットサーフィンが捗りコマンドが終わってからも十数分くらい想定していない時間の使い方をしてしまうことがあります。
最初から長くなるのがわかっているときは、以下のようにafplay
コマンドを使って音を鳴らすようにしていました。
$ npm run deploy; afplay /System/Library/Sounds/Purr.aiff
この方法では、たまたま実行したコマンドがの実行時間が長かった場合に、音を鳴らすためには一度実行を止めなければなりません。
そこでシェルのフック機能を使って、コマンド実行が長かった場合は自動的に音が鳴るようにしてみました。
シェルの実行時フック
シェルでコマンドの実行前後をフックするという記事を参考にしました。僕はzshを使いつづけているのですが、zshではコマンド実行後というフックがないため、プロンプト表示前を代用としてフックすると良いそうです。 そのままではコマンドを入れずにreturnを叩いたときにもprecmdが動くので、preexecでフラグを立てておいて、それがある場合のみ実行してフラグを倒す、などの対応が必要そうです。
autoload -Uz add-zsh-hook add-zsh-hook preexec my_preexec add-zsh-hook precmd my_precmd my_preexec() { echo "preexec" } my_precmd() { echo "precmd" }
元記事にはfishとbashでの方法も書かれていました。
時間の取得
date +%s
でunix timestampがとれます。
組み合わせる
上記を組み合わせて、このような形で実装しました。
autoload -Uz add-zsh-hook if [ "$(uname)" = 'Darwin' ]; then add-zsh-hook preexec my_preexec add-zsh-hook precmd my_precmd fi my_preexec() { MY_START_TIME=`date +%s` } my_precmd() { if [ -n "$MY_START_TIME" ]; then MY_END_TIME=`date +%s` MY_TIME_DELTA=`expr $MY_END_TIME - $MY_START_TIME` if [ $MY_TIME_DELTA -ge 20 ]; then afplay /System/Library/Sounds/Glass.aiff fi unset MY_START_TIME unset MY_END_TIME unset MY_TIME_DELTA fi }
- macOSの場合のみフックを登録するようにしておく
preexec
で開始時間を変数に取るprecmd
で開始時間と終了時間の差分を取って、20秒以上経っている場合は音を鳴らす- preexecで保存した開始時間は毎回
unset
で消去して、開始時間がある場合のみprecmd
が実行されないようにしておくことで、空打ちに対処する
- preexecで保存した開始時間は毎回
その他
僕はMacからの音が聞こえる環境で作業しているのでafplayで事足りのですが、音を出せない環境で作業されている方は通知センターを使ってみてはいかがでしょうか。 ターミナルからmacの通知センターに投稿する