DEV Community

Cover image for A Simple Pomodoro CLI
Byron Salty
Byron Salty

Posted on • Updated on

A Simple Pomodoro CLI

I've long been a fan of the Pomodoro Technique and recently I was looking to restart using it to focus my work. However, I ran into some problems finding the right tool for me. Below you'll see how I solved this problem and maybe this walk through will help someone.

Although the name of the Technique comes from seemingly ubiquitous kitchen timer that looks like a tomato (pomodoro in Italian), I do not have such a device. I was also looking for a solution that was all digital and that easily moved with me where ever I'm traveling and across computers so that I could better create the habit of using this time management technique.


Existing Solutions

Tomato Timer
I admittedly did not do a super exhaustive look into the space. I have also used the Tomato-Timer site for many years. I like it. Check it out.
However, I realized I wanted to play with different durations of working periods. Tomato-Timer follows the Pomodoro Technique strictly so you'll get a 25 minute working period and either a 5 or 10 minute break period.

Pomo
Pomo is another CLI (command line interface) solution. It looks very mature and full featured. I haven't used it personally but it looks good if you're looking for graphics related to status of your poms and it looks like it integrates into your projects to allow for time tracking. It does allow you to adjust durations of poms so this checked that box for me. [If you've used it let me know if my understanding is inaccurate and I'll update.]

However, I'm looking for something dead simple. I don't need graphics, a UI, integrated workflows, a server running, or an underlying datastore. Eventually maybe I'll have a need for such things but right now let's start with something more simple.


Something More Simple

So where to turn next? Why not just make a (very) little shell script that does exactly what I need.
What do I need exactly?
I want to kick off a pom for a variable number of minutes (default 25), have it run in the background, and play a sound when it's complete (I'm not going to watch it - I'm going to be working).

$ pom 5
Waiting 5 minutes
Timer is done // Note: sound plays
Enter fullscreen mode Exit fullscreen mode

No big deal right? I think this can be done in a few minutes.

Shell Script

The above requirement is relatively easily done with just a few lines of shell script. I did this on MacOS but I'm sure with Linux and now Windows it would be trivial to make a similar version if this doesn't directly work there.
This plays to one of my favorite architectural guides - The Unix Philosophy - which emphasizes simplicity and modularity. Which also is the foundation for all of the sweet command line goodies you already use.

Playing Sound

I thought this might be difficult but it turns out to be very easy to make sounds with Mac and I assume the same on any OS. I went with the text to speech solution of "say"

$ say Done
Enter fullscreen mode Exit fullscreen mode

Bonus points: Entertain the kids…

$ say its time for bed
Enter fullscreen mode Exit fullscreen mode

Waiting

Sleep is a pretty standard command and with it we can build a very small version of the end goal: A script that will just sleep a bit of time and then use 'say' to tell you the wait is done.

sleep 60
say "Done"
Enter fullscreen mode Exit fullscreen mode

Doing the Math

Notice that 'sleep' works in seconds and I wanted to give input in minutes so let's do some math. This actually was the trickiest part of the whole script, I guess because I just hadn't done much math in shell scripts before.
I just had to use 'let' and the script was finicky about spaces, but the incantation looks like this:

let seconds=1*60
sleep $seconds
say "Done"
Enter fullscreen mode Exit fullscreen mode

Taking Input

A primary requirement of the solution is giving the user the ability to chose their own duration of the pom. I would take in a number of minutes and default it to the standard 25 from the official Technique.

I'm going to have to use the built-in $1 variable which is the standard 1st position parameter into the script, this will tell me the value of what's passed in. But we also want to allow for a default of nothing passed in so we'll need to check the input.

if [ -z "$1" ]; then
 let min=25
else
 let min=$1
fi
echo "Waiting ${min} minutes"
Enter fullscreen mode Exit fullscreen mode

Putting this into an executable file named "iftest" for now:

$ ./iftest
Waiting 25 minutes

$ ./iftest 5
Waiting 5 minutes
Enter fullscreen mode Exit fullscreen mode

Putting It All Together

Now just a few echos to tell the user that things are happening as expected and voila!

if [ -z "$1" ]; then
 let min=25
else
 let min=$1
fi
let seconds=$min*60
echo "Waiting ${min} minutes"
sleep $seconds

msg="Timer is done"
say $msg
echo $msg
Enter fullscreen mode Exit fullscreen mode

Final result

Pull down the working pom command here.

Top comments (2)

Collapse
 
rouilj profile image
John P. Rouillard

Nicely done. A few tweaks for people using it on a pure posix shell:

You can also specify a default value when you substitute a value.
Replace:

if [ -z "$1" ]; then
 let min=25
else
 let min=$1
fi
Enter fullscreen mode Exit fullscreen mode

with

min=${1:-25}
Enter fullscreen mode Exit fullscreen mode

Also let (let seconds=$min*60) can be replaced with:

seconds=$(expr $min \* 60)
Enter fullscreen mode Exit fullscreen mode

the \* is needed to prevent * from trying to expand to all the files in the directory.

These changes let it work in basic posix shells like ash and dash as well as shells like bash, ksh and IIRC zsh.

Collapse
 
byronsalty profile image
Byron Salty

Hell yeah. Thanks man!