Ebooks, Hazel, and xargs

Although I have a Kindle, I prefer reading ebooks on my iPad, and the ebook reader I like the most is Marvin.1 This means I have to convert my Kindle books to ePubs (the format Marvin understands) and put them in a Dropbox folder that Marvin can access. The tools I use to do this efficiently are Calibre, Hazel, and, occasionally, a one-liner shell script.

If you have ever felt the need to convert the format of an ebook, you’ve probably used Calibre, so I won’t spend more than a couple of sentences describing how I use it.2 When I buy I new book from Amazon, it gets sent to my Kindle. I then copy the book from the Kindle into the Calibre library and convert the format to ePub. This doesn’t do the conversion in place and overwrite the Kindle file; it makes a new file in ePub format.

Calibre organizes its library in subfolders according to author and book. At the top level is the calibre folder, which I keep in Dropbox. At the next level are folders for each author. Within these are folders for each book from a particular author. Finally, within each book folder are the ebook files themselves and some metadata.

Calibre folder structure

This is great, but I find it easiest to configure Marvin to download ePubs from a single Dropbox folder, one that I’ve cleverly named epubs. So I want an automated way to copy the ePub files from the calibre folder structure into the epubs folder.

This is a job for Hazel. Following Noodlesoft’s guidance, I set up two rules for the calibre folder.

Hazel Calibre rules

The first one, “Copy to epubs,” just looks for files with the epub extension and copies them to the epubs folder.

Hazel ePub copy rule

By itself, this rule does nothing, because the ePub files aren’t in the calibre folder itself, they’re two levels down, and Hazel doesn’t look in subfolders without a bit of prodding. That prodding comes from the “Run on subfolders” rule:

Hazel subfolders rule

This action was copied directly from Noodlesoft’s documentation, which says

To solve this problem [running rules in subfolders], Hazel offers a special action: “Run rules on folder contents.” If a subfolder inside your monitored folder matches a rule containing this action, then the other rules in the list will also apply to that subfolder’s contents.

With these rules in place, I don’t have to remember to copy the newly made ePub file into the epubs folder—Hazel does it for me as soon as it recognizes that a new ePub is in the calibre folder structure.

At least it should do it for me. Sometimes—for reasons I haven’t been able to suss out—Hazel doesn’t make the copies it’s supposed to. I’ll open up Marvin expecting to see new books ready to be downloaded to my iPad, and they won’t be there. When that happens, I bring out the heavy artillery: a shell script that combines the find and xargs commands to copy any and all ePubs under the calibre directory into the epubs directory. The one-liner script, called epub-update, looks like this:

#!/bin/bash

find ~/Dropbox/calibre/ -iname "*.epub" -print0 | xargs -0 -I file cp -n file ~/Dropbox/epubs/

The find part of the pipeline collects all files with an epub extension (case-insensitive) under the calibre directory and prints them out separated by a null byte. This null separator is pretty much useless when printing out file names for people, but it’s great when those files are going to be piped to xargs, especially when the file names are likely to have spaces within them.

The xargs part of the pipeline takes the null-separated list of files from the find command and runs cp on them. In the cp command, file is used as a placeholder for the file name and the files are copied to the epubs directory. The -n option tells cp not to overwrite files that already exist.

The advantage of using epub-update when Hazel hiccups is that I don’t have go hunting through subfolders to find the file that didn’t get copied.

I suppose if I were smart, I’d set up my Amazon account to send new purchases to my Mac instead of my Kindle. Then I could automate the importing of new ebooks into the Calibre library and eliminate more of the manual work at the front end of the process. One of the advantages of doing posts like this is that the process of writing up my workflows forces me to confront my own inefficiencies.


  1. iBooks doesn’t give me the control over line spacing and margins that Marvin does. I may change my mind after seeing the all-new, all-improved Books app in iOS 12, but even if I switch, the automations described here will still be useful. 

  2. Also, because it has the worst GUI of any app on my Mac, I can’t bear to post screenshots of it.