GeekTool and Twitter FTW.
(As a moderate Twitter user but total geek, I’ve been meaning to write this for a while. Hopefully someone finds some usefulness in it.)
(Before someone comments, I know this could be done with a command line Twitter client, or I could just write one Python/PHP/etc. program to do it, but that would entirely be missing the point. Command line tools are extremely powerful and fun to use once you get some experience with them!)
The original idea for this came from The Apple Blog, but it has been heavily modified.
My desktop tends to be quite busy, and even with two 24″ screens, I find that I’m constantly out of screen real estate and don’t want to have yet another client open to display my Twitter stream. GeekTool to the rescue. GeekTool allows you to display the output of a shell script or a URL or file to the screen and refresh it at some defined frequency.
First, here’s a screenshot of what it looks like having my most recent 15 tweets visible on the screen, and what this tutorial is going to cover:
![]() |
| From Diminished Effect Pics |
And here’s the command that creates it (GeekTool refreshes it every 4 minutes):
curl -s -u username:password http://twitter.com/statuses/friends_timeline.rss | egrep “<title>|<pubDate>” | head -n 31 | tail -n 30 | sed -E ‘s/^[ ]+//’ | sed -n -E ’1h;1!{;/<title>.+<\/pubDate>/ !H;g;/<title>.+<\/pubDate>/ {;s/<title>(.+)<\/title>.+<pubDate>.+([0-9]{2}:[0-9]{2}:[0-9]{2}).+<\/pubDate>/\2 – \1/g;p;n;h;};h;};$p’ | sed -E ‘s/$/<br>/’ | /Users/scott/bin/modtime.py | /opt/local/bin/w3m -dump -cols 170 -T text/html
First a tiny bit about shell scripting for those unfamiliar. When you are in a terminal session (ie. run terminal.app on your Mac, from the /Applications/Utilities folder) you can run commands by typing them in and pressing enter. If you want to run multiple commands, passing the output from the first into the second and so on, you use the | (pipe) symbol. That way, the only output you will see at the end is the output from the last command.
The first segment of the shell script is this:
curl -s -u username:password http://twitter.com/statuses/friends_timeline.rss
The curl program fetches the contents of a URL. The -s option tells it to do it silently (ie. only display the output of the URL, not a progress meter as it is pulling the data). The -u option tells curl to use the following username:password combination — your Twitter username and password. Run that in the terminal program and you’ll see all of your recent Twitter timeline with a lot of extra information.
The next command in the chain is:
egrep “<title>|<pubDate>”
grep (and egrep) look for certain lines in their input and pass *only* those lines to their output. In this case we’re looking for lines that contain the tag <title> which contains the contents of a Twitter post or the tag <pubDate> which follows after each Twitter message with the timestamp (GMT) of when that message was sent.
Run the combined version of the first 2 commands in the terminal to see the difference in the output:
curl -s -u username:password http://twitter.com/statuses/friends_timeline.rss | egrep “<title>|<pubDate>”
Okay, now I only want to see the 15 most recent posts in my timeline…the next 2 commands take care of that:
head -n 31 | tail -n 30
The head command says “only print out the top 31 lines”, that is, the first line which we don’t actually want and then 15 <title> and <pubDate> pairs. The tail command says “only take the last 30 lines (of the 31)” so that gets rid of the first line we didn’t want anyway. (It only came in because it has a <title> tag in it.)
Now we start some real processing:
sed -E ‘s/^[ ]+//’
sed is a stream editor; basically it will find text that you identify with a regular expression (regex) and replace it with other text. This first invocation of sed says “find the text identified by ^[ ]+ and replace it with nothing”. The symbols ^[ ]+ mean, “one or more contiguous spaces, starting at the beginning of the line”. This deals with the issue that there are 4 spaces at the beginning of every line that we don’t want/need.
The next line is both more interesting and much harder to explain in detail:
sed -n -E ’1h;1!{;/<title>.+<\/pubDate>/ !H;g;/<title>.+<\/pubDate>/ {;s/<title>(.+)<\/title>.+<pubDate>.+([0-9]{2}:[0-9]{2}:[0-9]{2}).+<\/pubDate>/\2 – \1/g;p;n;h;};h;};$p’
I won’t get into the gory description, but basically sed is intended to process lines one-at-a-time, but in this case I need the time from the second line of each pair added to the beginning of the first line. This mini-program in sed achieves that (and takes out the title and pubDate tags). As an example, it takes this:
<title>hodgman: But so many of the film’s reviews really seem to have the anti-nerd knives out.</title>
<pubDate>Sat, 07 Mar 2009 15:46:59 +0000</pubDate>
And turns it into this:
15:46:59 – hodgman: But so many of the film’s reviews really seem to have the anti-nerd knives out.
If you wish to proceed with any more customization before putting your command into GeekTool, you’ll need 2 things: a little programming experience and to have Xcode installed on your system. It’s a free download from Apple to get the most recent version. The additional customization will convert the time from GMT to your timezone and also clean up the output of some of the tweets a little bit. Continue on if interested, otherwise skip to the end.
The final sed command:
sed -E ‘s/$/<br>/’
…does a little bit of processing to add a <br> to the end of each line. It is needed to make the final command recognize that it should print each tweet on a new line.
The next command fixes the problem with the time (still in GMT):
/Users/scott/bin/modtime.py
Now, I admit, this is a cheat. I did it because I can’t quite figure out how to do the time conversion on the command line yet, so I wrote a small Python program to do it. Here’s the code for this program (the 3 lines inside the for loop should of course be indented, but WordPress is not allowing me to do it easily):
#!/usr/bin/python
import sys
from datetime import time, timedelta, date, datetime
from time import timezoneoutput = “”
for text in sys.stdin:
t = time(int(text[0:2]),int(text[3:5]),int(text[6:8]))
adjtime = datetime.combine(date.today(),t) – timedelta(seconds=timezone)
output += adjtime.strftime(“%H:%M”) + text[8:]print output
That turns the example line above into:
10:46 – hodgman: But so many of the film’s reviews really seem to have the anti-nerd knives out.
The last command:
/opt/local/bin/w3m -dump -cols 170 -T text/html
…does some text processing to get rid of html entities and turn them back into readable symbols. Note that w3m is not installed on a Mac by default, but can be installed easily using MacPorts (beyond the scope of this post).
Putting it all together:
Now open up GeekTool (it’s a preference pane, so you’ll find it in System Preferences) and select “New Entry” and put your assembled command into the command box and fill out the location section to your satisfaction and set the refresh rate (I use 4 minutes). You can see my setup below:
![]() |
| From Diminished Effect Pics |
I hope this quick tutorial provides value to anyone in the Apple AND Twitter AND GeekTool AND command-line-fearless group of potential readers. Leave any questions in the comments and I’ll try to respond to them.









This looks great.
Two questions: is it possible to display growl notifications for new tweets? and are links clickable? If not, is it possible to do that, or is that a limitation of Geektool?
Unfortunately a consequence of the way GeekTool works prevents the text from being live so you cannot have active links. Also, GeekTool seems to overwrite whatever ANSI color codes you use, so I can’t have syntax highlighting either.
As for Growl, this should be no problem as I believe you can pass to the system notifier from the command line, but I’ve never actually tried it.
Actually, this link should give you some more info on that:
http://www.macosxhints.com/article.php?story=20070602201030683
Cool, thanks
This is very cool! I don’t have Python so I left the Tweets in GMT but other than that I like it. Not because it uses Twitter so much but because of the other things I can adjust it to do. Thank you very much.
Any advice on making the python script spit out Daylight Savings Time? I love this tool so much, but being off an hour is making me nuts! haha!
Hi, I am a total noob trying to find a way to use geektool to display my tasks from remember the milk. I really only want to have the task displayed, I started trying to apply this tutorial to it. Unfortunately, when I get to the egrep part, the commsnd line appears to do nothing. I tried removing the tag as i didn’t see the tag in the rss code and just search for the title tag, but nothing seems to happen then either. Any suggestions?
I know that there is a way to create a table-like output with terminal commands, can that be added to this?
very nice, exactly what I was looking for. Nice complement to the gmail command-line script which has the same form
[...] script is pretty well documented and there are plenty of posts on it. I started with an article by Diminished Effect and changed it slightly to meet my formatting [...]
GeekTool and Twitter = Desktop Bliss « Stray Link said this on May 6, 2010 at 1:42 am |
I got it working with twurl, but my (modtime) date is an hour off.. not savvy enough with Python, yet to tweak..
and when the is on the ‘next’ line via carriage return or something, it stalls modtime…
otherwise.. works great.. also my geektool’d display stops updating after a while (that may be a Little Snitch / twurl-oauth issue, though)
edit: when the bracketted //close title// is on the next line.
Not working ur script .Reply