Skip to content

Automatically and Smartly Moving Fonts to a New Machine

I recently got a new computer at work, and after a week of using it I realized I was missing a few fonts. I wanted to move over the old fonts to the new machine, but I knew there would be some wrinkles.

An Aside About Library Folders

If you know OS X, you know that it allows for three levels of configuration1 :

  • The /System/Library directory affects everyone, and should be untouched by the user; this is for Apple only.
  • The /Library directory affects everyone, but can be changed by the user to make computer-wide changes
  • The ~/Library directories affect just the user whose home directory they’re in

Whenever an app needs, say, a preference for the desktop background, it looks through that list from bottom to top, so user settings override computer settings, which override the system defaults.

Alternatively, the system can amalgamate the list from the union of the group, so each level can contribute some items to the set, again with more specific levels overriding. This is exactly what it does with fonts; each level has a list, and the font list you see inside apps is the combination of all the lists. But if I have a custom copy of Apple Chancery in my ~/Library/Fonts directory, it will override the one in /System/Library/Fonts.

The Problem At Hand

So the problem I had is that, when I moved to the new computer, I copied my ~/Library folder as part of the move2. But some fonts I use were apparently in /Libary, despite my best efforts to keep my settings in my home dir.

But I couldn’t just copy all those files into my ~/Library, because I didn’t want some old version of a font sitting in my home dir blocking me from seeing the new updated font installed by the OS.

So I needed to look at each of the fonts from my old computer, see if they had analogues in the new computer somewhere, and only move them if they did not have an analogue.

The Solution

So I wrote a ruby script that does exactly that:

Font =, :hash) do
  def name

  def to_s
    "#{name} • #{hash} @ #{path}"

  def self.list_from_dir(dir_path)
    %x{md5 #{File.expand_path(dir_path)}/*} do |line|
      _, path, hash = /MD5 (@?(.*)) = (.*)/.match(line).to_a, hash)

new_fonts = Font.list_from_dir '~/Desktop/OldFonts'
user_fonts = Font.list_from_dir '~/Library/Fonts'
lib_fonts = Font.list_from_dir '/Library/Fonts'
sys_fonts = Font.list_from_dir '/System/Library/Fonts'
old_fonts = user_fonts + lib_fonts + sys_fonts

outcomes =

new_fonts.each do |font|
  if dup = old_fonts.detect {|f| f.hash == font.hash}
    puts "# #{} has hash match #{dup}"
    outcomes[:hash_match] += 1
  elsif dup = old_fonts.detect {|f| ==}
    puts "# #{} has name match #{dup}"
    outcomes[:name_match] += 1
    puts "cp '#{font.path}' ~/Library/Fonts/"
    outcomes[:move] += 1

puts "# #{outcomes.inspect}"

This script looks through a folder on your desktop named OldFonts for fonts. For each one, it looks to see if there’s an identical item in your ~/Library, /Library, or /System/Library folder. If it doesn’t find an identical one, it will match by name in the same directories. If it doesn’t find that, it spits out the command to move the file into your ~/Library/Fonts directory, so it will follow you the next time you move computers.

It does not move any files; it just gives you the commands you can run to do so. In these kind of cases, where a mistake would be very bad, I often like to write my scripts so that they output another script, and I can review that script before running it.

In my case, it matched 158 exactly, 68 by name, and it let me move 132 files. Writing this script was way quicker than figuring out what to do in those 358 cases, so it saved me some time; I hope it saves you time, as well!

  1. well, four if you count the network, but I don’t know if anyone does that anymore 

  2. as I’ve done for every move since the Public Beta in 2001; my home folder is very old and assuredly full of cruft, but also full of gems I’d never remember to pull on their own or recall how to do again if I had to start over