pbgrep: grep your clipboard history

I’ve used ClipMenu as my clipboard history manager for several years now: it’s unobtrusive, and does almost exactly what I need.

Except, you can’t search the clipboard history.

I keep thousands of items in my clipboard history, and today I was trying to find a specific item, that I know was in there. And I couldn’t find it after about a minute of scanning through submenus.

Now, ClipMenu can persist it’s history to disk, in ~/Library/Application Support/ClipMenu/clips.data. Which is a binary plist file.

We can view it using plutil:

$ plutil -p ~/Library/Application\ Support/ClipMenu/clips.data -o -

I made the decision to limit searching for single-line clips: this means I can grep for lines that contain:


Doing single-line matches means I can use grep (or, as I discovered later, ack), which should be faster than firing up a python interpreter.

My first iteration was:

$ plutil -convert xml1 ~/Library/Application\ Support/ClipMenu/clips.data -o - \
  | grep "<string>.*test.*</string>" -o

This works quite well, but includes the XML string tags. I did strip them out using sed, but this is an extra command. It turns out that grep’s regular expressions can’t handle positive lookahead/behind assertions, and Mac OS X’s grep does not support --perl-mode, so I reached for ack:

function pbgrep() {
  plutil -convert xml1 ~/Library/Application\ Support/ClipMenu/clips.data -o - \
    | ack "(?<=<string>).*$1.*(?=</string>)" -o

That now takes pride of place in my .bashrc, and I can pbgrep foo to my hearts content.

I guess I could (if there was only one match), put the value back into the clipboard. That might be kind-of nice.

Open in Textmate Service

Listening to the new podcast by the ever-present Dan Benjamin and the effervescent Merlin Mann today reminded me of the one Mac OS X service I wrote, that I use almost daily.

It allows me to right-click on the filename line in a python traceback, and have the file opened at that line in Textmate. If the file is part of an already open project, it will open in the project window (unless it is open in another window, in which case that may pop to front).

Fairly simple stuff, and should be easy to extend for other traceback/output types.