Utilities for a time aware shell

July 18, 2021 — Ulysse

When we’re coding, we are often forced to take a break due to some npm install, make test or else, but that’s fine, we can estimate the time those commands take since we are doing those a lot.

However, sometimes you stumble upon a new command, that will take a lot of time, and you won’t expect that. The issue here is that you don’t know how long it will take to run that one again. Hence you will be forced to either wait in front of your terminal, or come back way later to be sure it is not running.

I’ve had that issue tons of times, for instance trying to copy files with the aws CLI, or working with docker-compose. And I found some work-arounds to make sure I can better manage my time.

Use notifications

The great terminal-notifier is a good way to address that issue: just add ; terminal-notifier -message done to the end of a command you expect will take a long time, and you’ll be alerted as soon as the job is done.

If you like that solution, here’s a way to type less characters for this technique:

# Append NOTIF to your command to have a notification once it is done, clicking
# on the notification will focus a terminal.
alias -g NOTIF=';terminal-notifier -group endCommandNotif -activate com.apple.Terminal -ignoreDnD -sound default -message done'

This is unfortunately not enough, since you may not expect at all a command to last.

Choose a timed ZSH theme

This is a very effective and simple solution, as there are great themes for that. I’ll suggest for instance the crunch theme. I myself use a mix of crunch and robyrussell, which is time and git focused. I called it crunchrobby, you can give it a try if you want!

CRUNCH_BRACKET_COLOR="%{$fg[white]%}"
CRUNCH_TIME_COLOR="%(?:%{$fg[yellow]%}:%{$fg[red]%})"
CRUNCH_TIME_="$CRUNCH_TIME_COLOR%T%{$reset_color%}"

PROMPT="$CRUNCH_TIME_ "
PROMPT+=' %{$fg[cyan]%}%c%{$reset_color%} $(git_prompt_info)'

ZSH_THEME_GIT_PROMPT_PREFIX="%{$fg_bold[blue]%}git:(%{$fg[red]%}"
ZSH_THEME_GIT_PROMPT_SUFFIX="%{$reset_color%} "
ZSH_THEME_GIT_PROMPT_DIRTY="%{$fg[blue]%}) %{$fg[yellow]%}✗"
ZSH_THEME_GIT_PROMPT_CLEAN="%{$fg[blue]%})"

There is still a tiny issue with that solution: it is only ok for command lasting minutes. Yet sometimes you want to know a bit more precise how long it took. For instance, when I’m trying to find an instable test, I’d like to know how long it took to run it 100 times, so I instantly know if I can run it 1000 times without waiting too long.

Time commands

So, couldn’t the ideal solution just be to always prepend your commands with time? I don’t think so, as it would clutter way too much the terminal, for information that is useless more often than not…

That is why I created a tiny zsh plugin called zsh-command-time, which only prints time if longer than 5 seconds. Hence you’ll have timing for those long running commands, while not being bothered most of the time.

Wrap it up

I use all of those three solutions in my day to day work, and they help me manage my time spent on the terminal, and finding time for those tiny breaks we all love!

BONUS: Ruby IRB timings

If you don’t have an irbrc file yet, now may be a good time to create yours! Here’s mine as an example.

To have a similar way of working as in zsh with zsh-command-time, you may add this to your irbrc:

if IRB.respond_to?(:set_measure_callback)
  IRB.set_measure_callback do |context, code, line_no, &block|
    time = Time.now
    result = block.()
    now = Time.now
    diff = (now - time)
    puts 'processing time: %fs' % diff if IRB.conf[:MEASURE] && diff > 0.5
    result
  end
end

And now you’ll have timings as long as it is more than 0.5 seconds.