I use Markdown a lot, so I’m constantly creating files that end in the .md extension. For a while I wanted the very nice (& free for now!) app Mou to open those, but now I’ve switched to Sublime Text for my Markdown editing1. So when I click on foo.md, I want it to open in Sublime Text instead of Mou.

Most Mac users of even mid-level sophistication know the drill: right-click on any file ending in .md, choose Get Info (or just select the file & press Command-I), find the Open With section, select Sublime Text, press Change All, press Continue when asked if I’m sure, close the Info window, done. It’s been that way for years, & it works fine.

But I want to use the command line instead.

Why use the command line when the process is pretty easy to do with a GUI?

  • I can keep all my changes listed in one file, so I have a record of what I changed.
  • I can make all my changes at one time (like after I’ve done a clean reinstall), in a few seconds.
  • Periodically, I find that when I right-click on a file, the programs list shows duplicates, sometimes a lot of duplicates. After I fix that problem (using the command line, natch), I’d like to quickly re-set my default apps.
  • I like the command line.

So here’s how to do it. Before you can jump in, though, you need to install a program & also know how to gather a few pieces of key information. Let’s walk through those things first.


The program that makes it easy to change default apps via the command line is a free, open source app named duti2. You can grab the source code at Sourceforge3. Download it, untar it, cd into the directory, & then do the classic three steps4:

sudo make install

This results in the duti executable going in /usr/local/bin/ & its man page getting placed into /usr/local/share/man/man1/. Easy enough.

Find out the current default for an extension

Why do this? Just so I can verify the current default, & then verify that any changes I make took.

So what’s currently the default for .md? Let’s find out:

$ duti -x md

The three line result tells me:

  1. The name of the app
  2. The app’s location on your Mac
  3. The app’s bundle ID, a unique identifier for each program that normally is written in a reverse-domain-name style (like com.apple.mail or com.barebones.bbedit)

Find out the bundle ID for an app

I want to change from Mou to Sublime Text, so I need Sublime Text’s bundle ID. There are a couple of ways I could get this info.

If I knew that another file type foo already uses Sublime Text as its default, I could use duti -x foo & look at the third line of the results, as with Mou above.

OR I can use this one-line AppleScript:

$ osascript -e "id of app "Sublime Text 2"" 

This works for any app on your system, like this:

$ osascript -e "id of app "Espresso""

Or this:

$ osascript -e "id of app "Mailplane 3""

Change the default app

I know the extension I want to change (.md) & the bundle ID of the app that I want to open that extension (com.sublimetext.2), so let’s use duti to do it:

duti -s com.sublimetext.2 .md all

The -s means “set”. In order, I tell duti the bundle ID of the app, the extension of the files, & all means “all files with that extension”.

Now I verify my change:

$ duti -x md
Sublime Text 2.app
/Applications/Sublime Text 2.app

Create a shell script

Now let’s put everything together into a shell script that you can run anytime you need to. Copy & paste the script below into a file, save it as set_default_apps.sh, make sure it’s executable (chmod 755 set_default_apps.sh), & then run it when you feel like it.

Of course, you will want to change this script, specifically the here document you see that starts with { cat <<eof & ends with eof. For each line, put the bundle ID for the app you want to use, then a colon, and then the extension that you want to change so that it uses the bundle ID (com.sublimetext.2:md is a good example). I sorted my list by extension, but really, it doesn’t matter.


#  FILE:  set_default_apps.sh
#  DESCRIPTION:  Changes default apps for extensions
#  AUTHOR:  Scott Granneman (RSG), scott@chainsawonatireswing.com
#  COMPANY:  Chainsaw on a Tire Swing (http://ChainsawOnATireSwing.com)
#  VERSION:  0.1
#  CREATED:  09/17/2012 21:44:01 CDT

{ cat <<eof
} | grep . |
while IFS=$':' read bundle_id extension ; do
  # Grep to see if Bundle ID exists, sending stdout to /dev/null
  /System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister -dump | grep $bundle_id > /dev/null  
  # Save exit status (0=success & 1=failure)
  # If exit status failed, notify me & exit; if not, change default app for extension
  if test $status -eq 1 ; then
    echo "$bundle_id doesn't exist! Fix the script!"
    echo -e "\nChanging $extension so it opens with $bundle_id\n"
    duti -s $bundle_id .$extension all
    echo -e "Here's proof…\n"
    duti -x $extension
    echo -e "\n----------"

I hope this helps you as much as it helps me.

  1. While Sublime Text comes with built-in support for Markdown, the addition of Keyboard Maestro really makes things sing in a way that constantly amazes me with its combination of power & ease of use. Plus, if I decided that I hated Sublime Text tomorrow, I could easily move to another editor, since Keyboard Maestro works with anything. 

  2. Yes, there are other ways to do this without duti, but duti makes it really easy. Much easier than not using duti. So duti it is. 

  3. Seriously, Sourceforge? Old skool. I thought everyone had switched to GitHub by now. 

  4. Yes, you’ll need Xcode (or at least the command line tools, which you can get using the Components tab of the Downloads preferences panel of Xcode) installed to do this. I don’t know why the developer didn’t make a binary available.