Skip to content

Instantly share code, notes, and snippets.

@petethepig
Last active March 7, 2024 03:46
Show Gist options
  • Star 66 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save petethepig/2d29e8b7e2ebc808bfe760b632608966 to your computer and use it in GitHub Desktop.
Save petethepig/2d29e8b7e2ebc808bfe760b632608966 to your computer and use it in GitHub Desktop.
Alert yourself after a long-running task in terminal

Alert yourself after a long-running task in terminal

For the last few months I've been working on pyroscope, I’ve often found myself getting distracted when I run any long tasks in the terminal (tests / docker builds).

This little snippet helps me get back to what I was doing in the terminal by alerting me via a sound message and also a macOS notification.

demo

Instructions

Step 1. Install terminal-notifier:

brew install terminal-notifier

Step 2. Add the following code to .bash_profile:

# Open ~/.bash_profile and add these functions:

function timer_start {
  timer=${timer:-$SECONDS}
}

# this makes bash run timer_start every time you run a command
trap 'timer_start' DEBUG

function notify_when_done {
  timer_show=$(($SECONDS - $timer))
  unset timer
  # 10 is the notification threshold in seconds
  if (( ${timer_show} > 10 )); then
    # modify this section to fit your needs:
    say "Done with task"
    terminal-notifier -title "Terminal" -message "Done with task! Exit status: $? Time: ${timer_show}s"
  fi
}

# this makes bash run notify_when_done command after every command
if [ "$PROMPT_COMMAND" == "" ]; then
  PROMPT_COMMAND="notify_when_done"
else
  PROMPT_COMMAND="$PROMPT_COMMAND; notify_when_done"
fi

Update: for information on how to set this up on Linux or with other shells (fish / zsh) see Hacker News comments.

@l0b0
Copy link

l0b0 commented Feb 25, 2021

Thanks for the tip! My implementation

@gitowiec
Copy link

Thanks for the tip! My implementation

Thanks for the Linux version, it is much more useful for me!

@figbux
Copy link

figbux commented Feb 25, 2021

Thanks for the tip! My implementation

How it behaves with vim, manpages etc? They take quite a long time but they shouldn't alert

@c02y
Copy link

c02y commented Feb 25, 2021

If anyone is using fish-shell, https://github.com/franciscolourenco/done can be used for the same purpose, works on Windows/macOS/Linux

@l0b0
Copy link

l0b0 commented Feb 25, 2021

How it behaves with vim, manpages etc? They take quite a long time but they shouldn't alert

@figbux It'll alert for those. I'm not sure what an elegant workaround would look like (is it possible to detect whether the command was interactive or not?), but you could of course do something like this (untested):

if [[ "$(("$SECONDS" - "$__bashrc_command_start"))" -gt 60 ]] \
    && ! grep --fixed-strings --line-regexp --quiet --regexp=man --regexp=vim <<< "$__bashrc_command"

@bertrand-caron
Copy link

bertrand-caron commented Feb 26, 2021

My version for zsh, that excludes long-running commands like vim, etc.:

### Source: https://gist.github.com/petethepig/2d29e8b7e2ebc808bfe760b632608966
function timer_start {
  timer=${timer:-$SECONDS}
}

# this makes bash run timer_start every time you run a command
trap 'timer_start' DEBUG

function notify_when_done {
  timer_show=$(($SECONDS - $timer))
  unset timer
  # 15 is the notification threshold in seconds
  if (( ${timer_show} > 15 )); then
    # modify this section to fit your needs:
    printf \\a
    terminal-notifier -title "Terminal" -message "Done with task $1! Exit status: $? Time: ${timer_show}s"
  fi
}

# export command we are about to run, so we can inject it in the notification once done
preexec() {
	export _CMD=$1
}
# this makes zsh run notify_when_done command after every command
precmd() {
    if ! [[ ${_CMD} =~ '^(v|vim|ssh|gc|gs|gd) ' ]] {
	    notify_when_done ${_CMD}
    }
}
### END

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment