23

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.)

5
  • 14
    Why was this closed? It seems useful and makes perfect sense to me. Oct 6 '12 at 6:53
  • 1
    I agree, this is a good question and should not have been closed.
    – NorthIsUp
    Jan 29 '13 at 18:28
  • Seems like this similar question may answer it!
    – Brad Parks
    May 30 '16 at 17:52
  • I would like this question to be re-opened please.
    – pawamoy
    Apr 14 '19 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
    Dec 26 '19 at 13:33
1
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
  done

  (( 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
0

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).

2
  • Is what you wrote about precmd really correct? I can't find any information about any hook being triggered after command execution.
    – simeg
    Aug 3 at 15:40
  • @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
    Aug 5 at 1:59

Not the answer you're looking for? Browse other questions tagged or ask your own question.