Send Mac Notification When Long-Running Terminal Process Completes
Tiny shell startup script to send Mac system notification when a long-running terminal process completes.
I would run brew upgrade or pnpm install and just stare at the screen or find something else to burn the time. If I changed windows, I’d forget I was waiting for a terminal process.
Got AI to generate a small script. Been working great!
Worse: I had went away and checked back just to find it had failed. Update: I think it does not notify on failures. Future enhancement.
It’s really increased my productivity. or at least, perceived productivity. Either ways, I am happier to have this. Do send feedback if this improvements can be made!
[!warning] Unverified AI generated code I’m not familiar with shell. I’ve had AI add safeguards for exploits (e.g. string sanitisation) and annotated as much as possible, but I’m no expert. So no warranty from me. Will iterate and improve.
TIMEFMT=$'%J took %*E'
preexec() {
local cmd=${1[1,500]}
# store start time
typeset -g cmd_start=$EPOCHSECONDS
# sanitize command
local cmd=${1[1,500]}
cmd=${cmd//$'\n'/ }
cmd=${cmd//$'\r'/ }
cmd=${cmd//[^[:print:]]/?}
cmd=${cmd#-}
# truncate
(( ${#cmd} > 60 )) && cmd="${cmd[1,57]}…"
# ALWAYS overwrite (no stale state)
typeset -g cmd_title=$cmd
# flag for expected long-running commands
typeset -g is_expected_long_running=0
# can extend with e.g. `*node*` or *watch*
case "$1" in
*dev*|*start*|*serve*) is_expected_long_running=1 ;;
*) is_expected_long_running=0 ;;
esac
}
precmd() {
local exit_code=$?
local duration=$(( EPOCHSECONDS - ${cmd_start:-EPOCHSECONDS} ))
# Ignore common interruption signals:
# e.g. when stopping local dev server, don't need to notify
# 130 = Ctrl+C (SIGINT)
# 143 = SIGTERM
case "$exit_code" in
130|143) return 0 ;;
esac
# ignore expected long-running commands
(( is_expected_long_running )) && return
# Only notifies if delay is `n` seconds or longer; tweak value to taste
(( duration > 1 )) || return
# ignore on short-duration crashes
(( exit_code == 0 && duration < 10)) || return
# ignore spam
(( EPOCHSECONDS - last_notify < 3 )) && return
typeset -gi last_notify=$EPOCHSECONDS
local message
if (( exit_code == 0 )); then
message="🟢 Completed in ${duration}s"
else
message="🔴 Failed (${exit_code}) after ${duration}s"
fi
$(command -v terminal-notifier) \
-title "$cmd_title" \
-message "$message" \
-sound default
} ↗ External Resources
- julienXX/terminal-notifier: Send User Notifications on macOS from the command-line.github.com
- related: jml/undistract-me: Notifies you when long-running terminal commands completegithub.com