Is there an equivalent of zsh's precmd for performing a function after a command has completed?

I'm looking for a way to send myself a notification for any process that takes over 60 seconds. Zsh has a great ability to print a summary of the resources used for each command if the command takes longer than the value set in REPORTTIME seconds. From what I can tell, the only available option is to print the format in TIMEFMT.

(More specifically, I'm looking to send myself a notification with https://pushover.net/ if any process running in a detached tmux session takes over 60 seconds to complete.)

  • 15
    Why was this closed? It seems useful and makes perfect sense to me. Commented Oct 6, 2012 at 6:53
  • 1
    I agree, this is a good question and should not have been closed.
    – NorthIsUp
    Commented Jan 29, 2013 at 18:28
  • Seems like this similar question may answer it!
    – Brad Parks
    Commented May 30, 2016 at 17:52
  • I would like this question to be re-opened please.
    – pawamoy
    Commented Apr 14, 2019 at 14:10
  • Have you tried notify-send --urgency=low -i "$([ $? = 0 ] && echo terminal || echo error)" "$(history|tail -n1|sed -e '\''s/^\s*[0-9]\+\s*//;s/[;&|]\s*alert$//'\'')"?
    – JW0914
    Commented Dec 26, 2019 at 13:33

2 Answers 2


You can use preexec to start counting time since execution and then precmd which runs after command execution finishes and before prompt is drawn to evaluate whether you want or not notification (and send it).

  • 1
    Is what you wrote about precmd really correct? I can't find any information about any hook being triggered after command execution.
    – simeg
    Commented Aug 3, 2021 at 15:40
  • 1
    @simeg There is no hook after specific execution but you can use precmd which is first thing that runs after finishing the previous command (even before printing out prompt). So yes, I believe it is correct.
    – blami
    Commented Aug 5, 2021 at 1:59
notify() {
  emulate -L zsh  # Reset shell options inside this function.

  # Fetch the last command with elapsed time from history:
  local -a stats=( "${=$(fc -Dl -1)}" )
  # = splits the string into an array of words.
  # The elapsed time is the second word in the array.

  # Convert the elapsed minutes (and potentially hours) to seconds:
  local -a time=( "${(s.:.)stats[2]}" )
  local -i seconds=0 mult=1
  while (( $#time[@] )); do
    (( seconds += mult * time[-1] ))
    (( mult *= 60 ))
    shift -p time

  (( seconds >= 60 )) &&
      print -r -- "'$stats[3,-1]' took $time seconds"
  # Replace the `print` statement above with your notification call.

  return 0  # Always return 'true' to avoid any hiccups.

# Call the function above before each prompt:
autoload -Uz add-zsh-hook
add-zsh-hook precmd notify

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .