The past couple of days I’ve been playing around with GeekTool a nifty litlle application that can show text files, unix commands output (including scripts), or images (local and from the internet) on your desktop. There are many sites with examples out there which inspired me to create a GeekTool setup of my own.
I started playing around with several scripts and GeekTool because it looked cool at first and it was fun to do some shell scripting. As the amount of information displayed on my desktop grew I started wondering why I was creating a lot of small processes taking up a little CPU time. I hardly ever look at my desktop because of all the windows in front of it. But the stats now on my desktop are easily accesable with one key (F11), and some starts are already displayed in either the menu bar or my iStat Pro widget. Removing it there gives me more room in the menu bar (which is starting grow full of icons) and saves some resources used by the widget.
Now I shall explain the GeekTool entries I created more detailed.
Battery
You can get a lot of information about your battery with the ioreg command. I found a battery status script which doesn’t work on leopard but with plenty of comment in the code to use it as a reference for the output of ioreg and write a little script of my own which prints the status, charge and time remaining. The code should be pretty self-explanatory.
#! /bin/sh
#
# Battery status script, writen by Ronald Chu for GeekTool usage. Free to
# use as you please.
#
# Prints the current charge, time remaining on battery power or the AC
# power status
# Create an array (Capacity, Voltage, Flags, Current, Amperage, Cycle Count)
# in 10.6 the order has changed to (Amperage, Flags, Capacity, Current, Voltage, Cycle Count) so we need to re-order
if [ -n '`sw_vers |grep ProductVersion:.10.6`' ]; then
status=(`ioreg -w0 -l|grep LegacyBatteryInfo|sed -e 's/[^1234567890]/ /g'|awk '{print $3" "$5" "$2" "$4" "$1" "$6}'`)
else
status=(`ioreg -w0 -l|grep LegacyBatteryInfo|sed -e 's/[^1234567890]/ /g'`)# Fix Amperage (convert large number to negative one)
status[4]=$(expr ${status[4]} + 0)
fi
# if charger connected
if [ $((${status[2]} & 1)) == 1 ]; then
#if battery is charging
if [ $((${status[2]} & 2)) == 2 ]; then
# Calculate minutes until fullycharged
if [ ${status[4]} -lt 0 ]; then
mins=''
else
mins=`echo "(${status[0]}-${status[3]})*60/${status[4]}"|bc`
if [ $mins -gt 59 ]; then
mins=`printf ", %d:%02d until full" $(( mins / 60 )) $(( mins % 60 ))`
else
mins=`printf ", 0:%02d until full" $mins`
fi
fi
echo `echo "${status[3]}*100/${status[0]}"|bc`"% (charging$mins)"
else
perc=`echo "${status[3]}*100/${status[0]}"|bc`
if [ $prec -lt 100 ]; then
echo "$perc% (not charging)"
else
echo "100% (charged)"
fi
fi
# if charger not connected
else
# Calculate minutes until empty
if [ ${status[4]} -ge 0 ]; then
mins=''
else
mins=`echo "- ${status[3]}*60/${status[4]}"|bc`
if [ $mins -gt 59 ]; then
mins=`printf "(%d:%02d remaining)" $(( mins / 60 )) $(( mins % 60 ))`
else
mins=`printf (0:%02d remaining)" $mins`
fi
fi
echo `echo "${status[3]}*100/${status[0]}"|bc`"%$mins"
fi
Hard disk
I only care about the free space on my main hard disk and not at all in what other drives, shares, disk images and so forth are mounted. So I filter and reformat output of df to show just that.
df -h | grep 'disk0s2' | awk '{print $4" free ("$5" of "$2" used)"}'
Memory
Calling top and extracting the memory usage is pretty simple. I am planning to extract much more information from top (like the load en processes using the most CPU time) later.
top -l 1 | awk '/PhysMem/ {print $8 " used, " $10 " free"}'
Network
I’ve written a bash script that takes the name of a network interface as a parameter and returns its status, IP address, the SSID if it is an airport connection and last but not least the amount of data sent and recieved. The comment in the code should explain everything.
#! /bin/sh
#
# Network status script, writen by Ronald Chu for GeekTool usage. Free to
# use as you please.
#
# Prints status, ip, trafic and (if aplicable) SSID name of the airport and
# ethernet connection. Network IO is stored with timestamp in milliseconds
# in a text file so with the difference in time and bytes the IO in bytes
# per second can be calculated.
workdir="/Users/ronaldchu/Applications/Scripts/GeekTool/"
# parameter is a number of bytes * 100 (for float precision)
function formatBytes()
{
if [ $1 -lt 102400 ]; then echo `echo "scale=2; $1/100"|bc` b; else
if [ $1 -lt 104857600 ]; then echo `echo "scale=2; $1/102400"|bc` Kb; else
echo `echo "scale=2; $1/104857600"|bc` Mb;
fi
fi
}
# The script takes the name of the interface as a parameter
if [ $# -lt 1 ]; then
echo "Parameter missing"
exit 1
fi
# Check if interface exists
ifconfig $1 > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "Interface \"$1\" does not exist"
exit 2
fi
#Extract ip adress
ip=`ifconfig $1 | grep "inet " | grep -v 127.0.0.1 | awk '{print $2}'`
if [ $ip ]; then
# Make IO info string "
IO_now="`${workdir}milliseconds` `netstat -ib | grep -e "$1" -m 1 | awk '{print $7" "$10}'`"
# If there is an old IO info file
if [ -f "${workdir}NetworkStatus_$1_IO.txt" ]; then
IO_old=`cat ${workdir}NetworkStatus_${1}_IO.txt`
# else create one and sleep for a second
else
echo $IO_now > ${workdir}NetworkStatus_${1}_IO.txt
IO_old=$IO_now
sleep 1
IO_now="`${workdir}milliseconds` `netstat -ib | grep -e "$1" -m 1 | awk '{print $7" "$10}'`"
fi
#calculate IO trafic in Kb/s
IO_in=`echo $IO_old $IO_now|awk '{print "scale=0; (100*("$5"-"$2"))/("$4"-"$1")"}'|bc`
IO_out=`echo $IO_old $IO_now|awk '{print "scale=0; (100*("$6"-"$3"))/("$4"-"$1")"}'|bc`
# Write current IO info
echo $IO_now > ${workdir}NetworkStatus_${1}_IO.txt
# Echo network status (with SSID iff the network interface is the airport)
if [ $1 == "en1" ]; then
SSID=`/System/Library/PrivateFrameworks/Apple80211.framework/Versions/Current/Resources/airport -I|grep '[^B]SSID' |sed -e 's/^[^:]*: //'`
echo "$ip ($SSID) `formatBytes $IO_in`/s down `formatBytes $IO_out`/s up"
else
echo "$ip `formatBytes $IO_in`/s down `formatBytes $IO_out`/s up"
fi
else
echo "Disconnected"
fi
To obtain the timestamp for the network data readings using date isn’t accurate enough, so I use the following little C program to get a more accurate timestamp.
#include <stdlib.h>
#include <sys/time.h>
main()
{
struct timeval tv;
gettimeofday(&tv, NULL);
printf("%d.%d\n", tv.tv_sec, tv.tv_usec);
}
What else can I do? Well, whenever you want add something fancy you can always do something with Twitter! It makes you modern and Web 2.0, and stuff like that. Also it was extremely easy to add the latest tweets from my friends to my desktop with only one single command.
curl -u username:password http://twitter.com/statuses/friends_timeline.rss?count=20| \ grep title|\ tail -n 20 |\ sed -e 's/.*\(.*\)<\/title>/\1/'
iTunes
For information on the track currently playing in iTunes I’ve combined several scripts and ideas from others and myself to create an applescript which extracts the album art and returns the artist, title and album of the current song. Add another entry in GeekTool to show the image, which is a PNG file in a fixed location. In my case, this is located at file:///Users/ronaldchu/artwork.png
# iTunesCurrentSong.scpt # # An applescript which returns the title, artist, album and player # status of iTunes and writes the current album art (or blank if # iTunes not running, or a default image if no art available) to a # png file # # Network status script, writen by Ronald Chu for GeekTool usage. Free to # use as you please. # folders specs set artworkFolder to ((path to home folder) as text) & "Applications:Scripts:GeekTool:" set artworkFile to artworkFolder & "artwork.png" set artworkiTunes to artworkFolder & "artwork.pict" set artworkBlank to artworkFolder & "blank.png" set artworkDefault to artworkFolder & "default.png" set unixArtworkFile to the quoted form of POSIX path of artworkFile set unixArtworkiTunes to the quoted form of POSIX path of artworkiTunes set unixArtworkBlank to the quoted form of POSIX path of artworkBlank set unixArtworkDefault to the quoted form of POSIX path of artworkDefault # Check if iTunes is running tell application "System Events" set powerCheck to ((application processes whose (name is equal to "iTunes")) count) if powerCheck = 0 then # If there's no iTunes running use the Blank Arwork do shell script "cp " & unixArtworkBlank & " " & unixArtworkFile return "" end if end tell tell application "iTunes" # Get current track name and status try set playerstate to (get player state) end try if playerstate = paused then set trackPaused to " " else set trackPaused to "" end if if playerstate = stopped then # If there's iTunes use the default Arwork. do shell script "cp " & unixArtworkDefault & " " & unixArtworkFile return " " end if set trackID to the current track set trackName to the name of trackID set artistName to the artist of trackID set albumName to the album of trackID (* Is there any Artwork? *) if (count of artwork of trackID) ≥ 1 then set artworkData to data of artwork 1 of trackID set fileRef to (open for access artworkiTunes with write permission) try set eof fileRef to 512 write artworkData to fileRef starting at 513 close access fileRef on error errorMsg try close access fileRef end try error errorMsg end try tell application "Image Events" launch set theimg to open artworkiTunes scale theimg to size 100 save theimg as PNG in artworkFile with replacing close end tell else (* If there's no Artwork use the default artwork. *) do shell script "cp " & unixArtworkDefault & " " & unixArtworkFile end if return trackPaused & " " & artistName & " " & trackName & " " & albumName end tell
For some reason the code contains html code for special character like < and &. I’ll look into this later, for now you just have to change that when copying the code. Also I’m having lot’s of difficulty with getting syntax highlighting working right, damnit…
Update 07/06/09: Changed the battery script so it will show “100% (charged)” instead of “100% (not charging)”.
Update 23/06/09: Please leave a comment if you like my scripts, or if you don’t. I’d love to get some feedback and know how many of the visitors google analytics reports to me are actualy using the scripts
Update 24/08/09: Updated the battery script, changed > to -gt to actualy do a greater-than comparisation instead of dumping into a file called 59.
Update 27/11/09: Added a version check to the BatteryStatus script because the order of the battery info has changed since 10.6

I started playing with GeekTool at the weekend, and I am keen to use your excellent sounding battery script. After creating the script file how do you get it to run in GeekTool.
I have just tried your twitter script and it appears untidy as it keeps the when it is displayed, can you remove the ?
Cheers
Steve
Save the battery script in a text file (eg.
~/Applications/Scripts/BatteryStatus.sh)and make it executable. Then add the full path of the script in GeekTool as a Shell Command (eg. Users/yourname/Applications/Scripts/BateryStatus.sh.I have just tried your twitter script and it appears untidy as it keeps the when it is displayed, can you remove the ?
What is untidy in the Twitter output?
I like the iTunes script.
How did you get the icons to work(battery?), or are they just part of the background?
They are part of the background. I’ve considered placing them with geektool so the icons of the network connections won’t show if the connection isn’t active but that would take up more resources.
The battery script is creating a text file titled “59″ at the root of my drive. Any ideas why?
Because I used
[ $mins > 59 ]which of course needs to be[ $mins -gt 59]. Thanks for pointing it out, it also explains the the unexplained ’59′ files on my hard drive :)Can’t get the network script to run. It is chmod’d to 777 and I get Parameter missing as the result. I’m missing something simple, I just know it
Add the missing parameter, namely the name of your network interface, for example
./NetworkStatus.sh en1. Useifconfigin your terminal to see active network connection(s) and their names.Hi. Thank you for your geektool codes. However, I’m having difficulty working on the iTunes artwork to be displayed on the desktop via GeekTool.
Could you help please?
Thanks
Hi Ronald. I finally got it working (the iTunes script) but one thing I noticed is the refresh rate… If I set it to1 sec, the image flickers after every second. If I put higher number, the image doesn’t update.
Perhaps if you set both entries to 1 sec the images flickers because it is being updated by the script? Refreshing of the image isn’t to great, I’ve set it to 10 sec but it can take up to 20 sec to display the correct image (first wait 10 sec for the script to run, than wait another 10 sec for the image to be updated). It’s not ideal.
Hi,
very cool scripts !!
Your background image is very cool. May I ask where I can download this picture
Thanks in advanced
Hi,
Good work.
About your network script. When testing this in mac mini I got results like -1.31b/s down and -.31b/s up when transferring lot’s of data.
#calculate IO trafic in Kb/s
IO_in=`echo $IO_old $IO_now|awk ‘{print “scale=0; (100*(“$5″-”$2″))/(“$4″-”$1″)”}’|bc`
IO_out=`echo $IO_old $IO_now|awk ‘{print “scale=0; (100*(“$6″-”$3″))/(“$4″-”$1″)”}’|bc`
when i tried to echo these variables i got :
bobby:geektool Booby$ echo $IO_old $IO_now
1008427297 4261400953 1008440624 4261407891
what are these variables $5 $6. Can you explain because I’dont understand.
@erno Thanks, I’ve made that goat several years ago, you can download it at rchu.nl/files/eldiablo.png
@Booby The $IO_old and $IO_now variables should contain three numerical values the first being the current UNIX time in miliseconds. Thats where the $5 and $6 variables come in. You’ve probably forgotten to compile the little C program listed below the network status script to return this time so the call to
milisecondsfails.I forgot that, but when tried to compile your C script got many errors.
cc -o test test.c
what I should do that I can compile it right…
Many thanks ;o)
@erno I’ve tried CC and GCC the same way you did and both give me a warning (incompatible implicit declaration of built-in function ‘printf’), but it compiles and works anyway. I have practically no expericence with C and made that program with lot’s of googling and trail and error, so I can’t really help you more than this.
You can get my compiled binary at http://rchu.nl/files/milliseconds, maybe that helps.
My friend solve that problem, these lines top of that code and it works. Don’t know anything about C but now I got cool scripts working…
#include
#include
#include
#include
main( )
….
@erno That doesn’t make sense to me. I have little C skills but quite some programming skills so I could just misguess C syntax here… Anyway, cool that everything is up and running!
I’m using your iTunes applescript with geektool 3 and it work great when I tunes is running and when current track has artwork. But it won’t change the artwork when iTunes quits and/or when the track has no artwork. Any suggestions?
MBPro 15″
OSX 10.6.1
GeekTool 3.0 RC5 (116)
thanks for the scripts.
having trouble making the battery one work. it displays something like 283% when the battery is fully charged and the charger is connected. the value changes if the charger is disconnected and seems to be reflecting the actual changes. and yet, nothing but ’283%’ (or whatever the current value is) on the display
@alex: I haven’t used the scripts since my upgrade to Snow Leopard, aparentely I don’t need GeekTool that much. Anyway, I noticed some strange behavior too and found out that since SL the order of the output of ioreg has changed. I’ve updated the script to detect SL and reorder if needed. It should work now.
My network tracking stays at .15b/s down 1.17b/s up. Is there a way to fix this?
@Jelmer I assume that you’ve tried generating lots of traffic, reset the connections and so forth. You could try to check the write permissions or just delete the NetworkStatus_*_IO.txt files which store the previous amount of data transmitted, though they should be updated each time the script runs.
I’m having some problems with your battery script, What do I type into GeekTools Command line for it to echo the script onto the desktop?
@Eddie Save the script as a plain text file (e.g.
~/Applications/batterystatus.sh, the.shextension, for shell script, is not required but common). Make it executable (chmod a+x ~/Applications/batterystatus.shon the terminal, replace the filename with the location you chose) and then enter the full path to that file as the command of a shell item in GeekTool.you suck really why to make all your script so hard to understand -.- no one is working only disk use bla bla and of the ram. network does work
How can I refresh geektool every millisecond???