Search code examples
macoscocoametadatacommand-line-tool

How can I add macOS "Tags" to files programmatically?


Since Mavericks, OS X has had the ability to tag & colour files in Finder.

finder tags

Is there any way to add tags to files through Cocoa APIs or via a shell command?


Solution

  • Sorry for adding another answer, but the one related to setting Label colors was pretty long already. Here is an excerpt from a python script that I use to set the User Tags. It seems to work to make things searchable, but not sure if the tags will show up correctly. Usage is basically:

    tagfile.py "Tag Name" FileOrFolderName
    

    Code below.

    #! /usr/bin/env python
    # -*- coding: utf-8 -*-
    
    """ Write tags to file
    Usage:
        tagfile.py "TagName" FileName1 FileName2 
    
        You can use wildcards for the file name. Use quotes if spaces in tags.
        To check if it worked, use xattr -l FileName
    
    """
    
    import sys
    import subprocess
    
    def writexattrs(F,TagList):
        """ writexattrs(F,TagList):
        writes the list of tags to three xattr fields on a file-by file basis:
        "kMDItemFinderComment","_kMDItemUserTags","kMDItemOMUserTags
        Uses subprocess instead of xattr module. Slower but no dependencies"""
    
        Result = ""
    
        plistFront = '<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><array>'
        plistEnd = '</array></plist>'
        plistTagString = ''
        for Tag in TagList:
            plistTagString = plistTagString + '<string>{}</string>'.format(Tag.replace("'","-"))
        TagText = plistFront + plistTagString + plistEnd
    
        OptionalTag = "com.apple.metadata:"
        XattrList = ["kMDItemFinderComment","_kMDItemUserTags","kMDItemOMUserTags"]
        for Field in XattrList:    
            XattrCommand = 'xattr -w {0} \'{1}\' "{2}"'.format(OptionalTag + Field,TagText.encode("utf8"),F)
            if DEBUG:
                sys.stderr.write("XATTR: {}\n".format(XattrCommand))
            ProcString = subprocess.check_output(XattrCommand, stderr=subprocess.STDOUT,shell=True) 
            Result += ProcString
        return Result
    
    DEBUG = False
    
    
    if __name__ == "__main__":
        if len(sys.argv) < 3:
            print __doc__
        else:
            TagList = [ sys.argv[1] ]
            # print TagList
            # Or you can hardwire your tags here
            # TagList = ['Orange','Green']
            FileList = sys.argv[2:]
    
            for FileName in FileList:
                writexattrs(FileName, TagList)