I run a lot of long commands. Tests, builds, migrations, deploys, big greps, the usual stuff. While they run I do something else, usually I read something, sometimes I work in another terminal. The annoying part is not the waiting, the annoying part is the checking back. Every 30 seconds I tab over to see if it’s done, and half the time it is not, and over the day this adds up to a surprising amount of wasted attention.
So I added this little thing to my ~/.zshrc:
function ding() {
"$@"
local exit_code=$?
if [[ $exit_code -eq 0 ]]; then
( afplay -v 0.2 /System/Library/Sounds/Pop.aiff >/dev/null 2>&1 )
else
( afplay -v 0.2 /System/Library/Sounds/Basso.aiff >/dev/null 2>&1 )
fi
return $exit_code
}That is it. I prefix any command I want to be notified about with ding:
ding pytest
ding npm run build
ding terraform applyPop.aiff plays on success, Basso.aiff plays on failure. The return $exit_code at the end means ding is transparent, I can chain it, pipe around it, use it in scripts, and the exit code is preserved. So nothing else in my workflow needs to change.
The first version of this played one sound. I still tabbed back to check if it had passed, so the whole thing was kind of pointless. With two sounds I do not have to do that any more: Pop means it worked, Basso means go look now. My ears do the triage for me.
I tried terminal-notifier first. Don’t bother. Notifications need the screen, they pile up, and they disappear the moment you are in a full-screen app, which is most of the time when I am working. A sound works while I am reading something else or on a call, and it does not stack on top of itself.
One parameter worth tuning is the volume. At full volume Basso makes me actually jump, which is the wrong reaction to a failed test. 0.2 is loud enough that I notice it, quiet enough that I can ignore it if I want to.