After years of Outlook and Palm synchronization, when I fully switched over to the Mac, I moved my contacts database over to Mac OS X’s Address Book (painfully due to Outlook’s roach motel tendencies, but that’s another story). For the most part I am satisfied, its data model is far more powerful than Outlook’s, and most Mac apps feature excellent Address Book integration. I can call someone using Skype just by right-clicking on a phone number, for instance.

I just noticed, however, that my scripted Address Book backups were pushing the bounds of the reasonable: over 60MB zipped. For a mere 357 contacts, that seems a tad excessive. Upon further inspection, I realized my Address Book directory ~/Library/Application Support/AddressBook was pushing 152MB, the bulk of it in the Images subdirectory.

It turns out there are two causes for this problem:

  1. When you drag and drop an image for a contact, then crop it, Address Book keeps the full-size image around, presumably in case you want to change the crop later. In most cases this is unnecessary and wastes space.
  2. Address Book does not seem to remove the images for a contact when you delete it. Worse, those images get carried over into manual backups and thus backing up, blowing away your Address Book directory and restoring from backup will not get rid of the cruft.

I wrote the short shell script below to back up the AB directory, extract the list of contacts and delete any image that fits in the two categories above. This took me down to a much more reasonable 11MB. You can download the zipped script here.

Disclaimer: I tried my best to make this as generic as possible, but I cannot be held responsible if running this script causes you to lose data, so I would advise you to perform your own backup prior to running it.

#!/bin/sh
backup=$HOME/ab_clean_backup.$$
in_ab=$backup/in_ab
all=$backup/all
datadir="$HOME/Library/Application Support/AddressBook"
db=`echo "$datadir"/*.abcddb`

exit_ab() {
  echo killing AddressBook
  ps -u `whoami` | grep "Address Book" | grep /Applications | awk '{print $2}'|xargs -n 1 kill -9
}

backup_ab() {
  echo "Backing up address book directory $datadir to backup $backup"
  rm -rf  $backup > /dev/null 2>&1
  mkdir $backup
  ditto "$datadir" "$backup"
}

remove_old() {
  echo extract list of contacts in AB from SQLite
  sqlite3 "$db" "select zuniqueid from zabcdrecord"|cut -d: -f 1|sort > $in_ab

  cd "$datadir"
  cd Images

  # comment out the next two lines if you want to keep full-size originals
  echo removing full-scale images
  rm -f *.jpeg

  echo finding all the images
  ls -1|grep -v '\.jpeg$'|sort > $all

  echo removing images with no associated AB record
  comm -13 $in_ab $all | xargs rm
}

exit_ab
backup_ab
remove_old