Let’s address the headline first. This post is about the tags on files that Apple started supporting in Mavericks. Up until iOS 11, they didn’t work on iOS devices, so they eventually became “Finder tags.” I think “Apple Tags” is going to have to be the nomenclature moving forward (now that they’re starting to work on iOS as well), but I don’t think it’s a widely accepted phrase yet. So I’ll use “Finder tags” for a little while longer.
I have a handful of scripts for manipulating tags from the command line, including the most complete (and useful to me) one, vitag. There’s an excellent CLI from James Berry called “tag” that I use frequently, but I sometimes implement more “down and dirty” techniques in scripts.1 If you’re just looking for a ready-to-go tool, grab tag and skip the rest of this.
Last weekend I wrote a script to handle cleaning up my system’s tags, merging synonymous tags, fixing spacing and punctuation, making casing and pluralization consistent, and various other nitpicks that have gotten messy in my taxonomy over time. It used the same basic Ruby classes that I used in vitag, which you can reference on GitHub for a more full-fledged version of these tips. I’m not ready to publish this last script yet, but I thought I’d point out a few simple tricks for those working on their own solutions.
Reading tags on a file
Tags are stored in extended attributes on the files, in a metadata attribute with the key kMDItemUserTags.
Not ideal:
Trying to view them using the xattr tool almost always results in a hex dump, and converting it results in a binary plist, and converting that gives you messy results.
I can parse that response, split lines, remove commas, etc., and turn it into an array of tags I can work with.
Writing tags to a file
Tags are written to files using xattr. They need to be passed to xattr in Plist format (XML) with an array of string elements containing the tags.
When you write tags to the file using xattr, it will obliterate any existing tags, so note that if you want to add tags instead of replacing them, you need to read the tags into an array as shown above, modify and update the array, then write the whole thing back to the file.
Here’s a Ruby snippet showing the building of the XML string and shelling out to write it to the file:
# File to operate onpath="~/Dropbox/nvALT2.2/ruby shellwords module.md"# Test array of tag stringstags_xml=[':snippet:ruby','shell']# begin valid PLIST XML stringplist=%Q{<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">}# array of tag names to array of xml stringtags_xml.map!{|tag|"<string>#{tag.title}</string>"}# Join the array strings and append to the plistplist+=%Q{<plist version="1.0"><array>#{tags_xml.join()}</array></plist>}# Shell out and run xattr to write the plist to the file's attributes%x{xattr -w com.apple.metadata:_kMDItemUserTags '#{plist}' '#{File.expand_path(path)}'}
Color labels
The colors associated with tags like “Blue” and “Orange” (default label names) are stored in a different attribute (com.apple.FinderInfo). This dates back a ways, and there’s really no point in directly writing to this attribute anymore. It’s easiest just to change the tags. Remove “Blue” and add “Orange.”
…will simply apply the Blue tag to the file automatically. So just apply the Blue tag and skip the hex strings.
In closing
I’ll stop there because I know this isn’t all of widespread interest. If you are looking into scripting any of this directly, I do recommend checking out the vitag code and James Berry’s tag project.
Often just for the sake of not having any external dependencies… ↩