Snowcrash
Snowcrash

Reputation: 86087

zsh: show time spent in command

I've got some long-running commands that can last 15 minutes or more.

Is there a way to output a dynamic "time spent" section in the output?

E.g.

$ `do something long`
10 mins 15 secs
Refreshing state...

then:

$ `do something long`
14 mins 15 secs
Refreshing state...
Output results
$ ... and we're done

Upvotes: 2

Views: 608

Answers (1)

Marlon Richert
Marlon Richert

Reputation: 6995

zmodload -F zsh/system p:sysparams # Load the sysparams table.
zmodload -F zsh/terminfo b:echoti  # Load the echoti builtin.

timed() {
  local +h -i SECONDS=0

  # Open an async process for the timer.
  local -i timer_fd
  exec {timer_fd}< <(
    # Print the process id, so we can kill it later.
    print $sysparams[pid] 

    echoti civis   # Make the cursor invisible.

    while true; do
      print "$(( SECONDS / 60 )) mins, $(( SECONDS % 60 )) secs"
      echoti cuu1  # Move the cursor up 1 line.
    done
  )

  # Read the timer process id.
  local -i timer_pid
  read timer_pid <&$timer_fd

  # Start another async process for the actual task.
  local -i task_fd
  exec {task_fd}< <(
    eval "$@"     # Run the task.

    # Close the timer fd and kill the timer process.
    exec {timer_fd}<&-
    kill -KILL $timer_pid

    echoti cnorm  # Make the cursor normal again.
  )

  # Redirect the output of the async processes to the terminal. This is
  # a blocking operation. Thus, we won't get past these two lines until
  # both async processes end.
  <&$timer_fd
  <&$task_fd

  exec {task_fd}<&-  # We're done. Close the task fd.
}

Example usage:

% timed 'sleep 855; print Output results'

References

Upvotes: 3

Related Questions