Automatically tagging files that were last opened more than x days ago

When a file is tagged in Finder it has an extended attribute set on it:

      com.apple.metadata:_kMDItemUserTags

General Information

The easiest way I've found to apply a custom tag to a file programmatically is to use xattr to get the value of a custom tag, not one of the default tags, and apply it to the target file(s) via a shell script. For example, I created a new custom tag named Review, giving it the color yellow. Its hex representation is:

62706C6973743030A101585265766965770A35080A0000000000000101000000000000000200000000000000000000000000000013 

      Hint: Mouse over and horizontal scroll to see full code.

To get the value of the custom tag's com.apple.metadata:_kMDItemUserTags extended attribute, after having set it normally in Finder, the following example compound command was use in Terminal, e.g.:

xattr -px com.apple.metadata:_kMDItemUserTags "/path/to/file" | tr -d '\n' | tr -d ' '

      Hint: Mouse over and horizontal scroll to see full code.

  • Note: When using the above example compound command the prompt is not returned as normal and is directly after the hex string instead of being on the next line, so when copying the hex string make sure not to copy any of the prompt!

The output of the xattr command to see standard output would be, e.g.:

$ xattr -l "/path/to/file"
com.apple.metadata:_kMDItemUserTags:
00000000  62 70 6C 69 73 74 30 30 A1 01 58 52 65 76 69 65  |bplist00..XRevie|
00000010  77 0A 35 08 0A 00 00 00 00 00 00 01 01 00 00 00  |w.5.............|
00000020  00 00 00 00 02 00 00 00 00 00 00 00 00 00 00 00  |................|
00000030  00 00 00 00 13                                   |.....|
00000035
$

      Hint: Mouse over and horizontal scroll to see full code.

However, for this purpose just the hex string is wanted, hence the use of the -px option previously, and why piping the output to the tr command to delete newlines, \n, and spaces is necessary.

Applying Custom Tag

To apply this custom tag in Terminal to a file for testing, use e.g.:

xattr -wx  com.apple.metadata:_kMDItemUserTags '62706C6973743030A101585265766965770A35080A0000000000000101000000000000000200000000000000000000000000000013' "/path/to/file"

      Hint: Mouse over and horizontal scroll to see full code.

  • Note: The xattr man page does show an example of copying the extended attribute from one directory to another, which can be applied to files too, however for a programmatic solution I prefer this method. See man xargs in Terminal for additional information.

Programmatic Usage

This could be used in a bash script or in Automator using a Run Shell Script action, however the Find Finder Items action and Filter Finder Items action in Automator has a bug with the Date last opened setting.

This leaves using the find command or the mdfind command, the latter being better at finding files for the Date Last Opened as shown in Finder in List view or the Get Info sheet for a given file, which is the kMDItemLastUsedDate attribute used with the mdfind command using a properly formed query. Note that mdfind does require Spotlight Indexing of the target directory, and is turned on by default.

In Terminal, this compound command example uses mdfind to locate files matching the query and its result it passed to xargs to run xattr on the files to apply the custom tag:

mdfind -0 -onlyin "$HOME/Documents" 'kMDItemLastUsedDate > $time.today(-7) && kMDItemLastUsedDate < $time.today(-6)' | xargs -0 -I % xattr -wx com.apple.metadata:_kMDItemUserTags '62706C6973743030A101585265766965770A35080A0000000000000101000000000000000200000000000000000000000000000013' %

      Hint: Mouse over and horizontal scroll to see full code.

How this gets wrapped in a shell script or in Automator using a Run Shell Script action and scheduled to run at a regular interval really depends on how one intends to schedule it and other criteria surrounding how one intends to take into account its usage and other controls so as not to just run wild, if you will.

I would probably choose to use launchd to schedule this as a bash script and stay away from Automator, that is depending on what else one is wanting to be a part of the overall process.

For testing purposes, under macOS High Sierra, this is what I did:

1. Create a bash script with the example mdfind compound command from above.

In Terminal:

mkdir ~/bin
cd ~/bin
touch crtag
open -e crtag

The last command above should, by default, open crtag, for [C]ustom[R]eview[Tag], in TextEdit, in which the following lines were added:

#!/bin/bash

mdfind -0 -onlyin "$HOME/Documents" 'kMDItemLastUsedDate > $time.today(-7) && kMDItemLastUsedDate < $time.today(-6)' | xargs -0 -I % xattr -wx com.apple.metadata:_kMDItemUserTags '62706C6973743030A101585265766965770A35080A0000000000000101000000000000000200000000000000000000000000000013' %

      Hint: Mouse over and horizontal scroll to see full code.

Saved the e.g. crtag document and closed it.

Back in Terminal, made crtag executable, e.g.:

chmod 0755 crtag

      Note: 0755 translates to: -rwxr-xr-x

2. Create a PLIST file for launchd to run the e.g. crtag shell script daily at the desired time.

In Terminal:

cd ~/Library/LaunchAgents
touch com.my.DateLastOpenedCustomReviewTag.plist
open -e com.my.DateLastOpenedCustomReviewTag.plist

The last command above should, by default, open com.my.DateLastOpenedCustomReviewTag.plist in TextEdit, in which the following lines were added:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>EnvironmentVariables</key>
    <dict>
        <key>PATH</key>
        <string>/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:</string>
    </dict>
    <key>Label</key>
    <string>com.my.DateLastOpenedCustomReviewTag</string>
    <key>ProgramArguments</key>
    <array>
        <string>/bin/bash</string>
        <string>/path/to/script</string>
    </array>
    <key>RunAtLoad</key>
    <false/>
    <key>StartCalendarInterval</key>
    <array>
        <dict>
            <key>Hour</key>
            <integer>9</integer>
            <key>Minute</key>
            <integer>00</integer>
        </dict>
    </array>
</dict>
</plist>

While setting /path/to/script to the actual fully qualified pathname, e.g. /Users/me/bin/crtag, and the time as shown in the <key>Hour</key>, <integer>9</integer> and <key>Minute</key>, <integer>00</integer> keys, which uses 24 Hour time.

Saved the e.g. com.my.DateLastOpenedCustomReviewTag.plist document and closed it.

Back in Terminal, loaded the e.g. com.my.DateLastOpenedCustomReviewTag.plist file for launchd to run the shell script, per its settings:

launchctl load com.my.DateLastOpenedCustomReviewTag.plist


Now every day at e.g. 9:00 AM, the files meeting the mdfind query will have the custom tag applied to them, which can be viewed in Finder from the Tags section on the Sidebar, or other Finder methods involving Tags.



Note: See the manual pages in Terminal for mdfind, launchd, launchctl, tr, xargs and xattr, e.g. man mdfind. Also have a look at: File Metadata Query Expression Syntax