ターミナルでビルドのような時間がかかるコマンドを実行中のあなた。そのスキマ時間を有効活用しようにも、コマンドの進捗確認のためにちらちら戻ってきてしまい集中できない……。
これを解決するシェルスクリプトを紹介します。コマンドの完了時、実行時間が設定以上の場合にデスクトップ通知をさせます。
先日長い処理には通知音コマンドを仕込んでおくと捗るぞという記事を読みました。
音だけじゃなくデスクトップ通知にしたい、手動でコマンドを仕込むのではなくシェル側がよしなにやってほしい、と考えていたところ、その記事のコメントでzsh-notifyが紹介されていました。
筆者の環境はzsh-notifyのサポート外でしたが実装を見たら意外と簡単であったため、zsh-notifyを参考にして実装しました。
- 時間がかかったコマンドの完了時にデスクトップ通知を送る
- 通知したくないコマンド(例:
nvim
や npm run dev
)をフィルター可能 - 短時間で終わるコマンドも手動で通知可能
筆者はZshで実装しましたが、他のシェルでもフック機能の部分を書き換えれば動きます。
先にスクリプトの全体を掲載します。
全体の流れは次のようになっています。
- コマンド実行直前
- コマンド実行後
- コマンドの終了時刻を取得する
- コマンドが非通知対象ならスキップ
- コマンドの実行時間が設定以上なら通知
「コマンドの実行直前」「コマンド実行後」に処理を仕込むにはシェルのフック機能を使います。
今回はZshなのでそれぞれpreexec
とprecmd
を使いました。
preexec
はコマンドの実行直前のフックです。一方、precmd
は次のプロンプトの表示直前のフックです。
Zshのフックの一覧はzsh: 9 Functionsに掲載されています。
別のシェルでも似たような機能で実現可能です。たとえばfishであればイベントハンドラ、bashであればbash-preexecなど。
グローバル変数に「実行するコマンド」と「実行の開始時刻」を記録します。
unset
しておかないと、通知後の次のコマンドで空のままEnter
を押したときなどに通知が出てしまいます。他にもやりようはありますが要はクリーンアップです。
EPOCHSECONDS
で時刻を取得できます。EPOCHSECONDS
はzsh: 22 Zsh Modulesに掲載されています。
開始時刻my_notify_start_time
を使って計算しています。
通知させたくないコマンドを配列に突っ込み、判定させる関数で使います。
WSL環境でデスクトップ通知させるために、Powershellのスクリプトを実行します。
上記だとps1の部分がハイライトされないので、ps1の部分だけのバージョンも掲載します。
参考
Macでの通知にはterminal-notifierを使いました。
インストールするツールを増やしたくない人はosascriptやafplayを使うとよいでしょう。
こんな感じで、各OSの通知処理をまとめた関数も実装します。
こうすることで、「もしかしたら速く終わるかもしれないから通知つけておきたい!」というコマンドでfoo; notify
のように通知を仕込むことができます。
意外と短い行数で実現できました。コマンドの進捗確認のチラチラタイムが無くなったので作業に集中しやすくなりました。