Zettelkasten Forum

[KM Macro] Open a File Outside the Zettelkasten Identified by a UID

This Keyboard Maestro macro will open the file in a specified directory with a filename containing the currently selected text. The intended use case is a UID scheme for documents outside the Zettelkasten; as such, the macro expects that only one file will match the search string.

As an example, a daily/diary note might contain a line like:

  • [[Project Name]]: The table of sources has grown too large and unwieldy for Markdown. Moved it into a spreadsheet (202007071949).

Double-clicking the spreadsheet's UID and triggering the macro will open the spreadsheet in the default application for its filetype.



  • I saw that you are using the find command. How fast is it for you? I've got basically the same action for my Zettelkasten Alfred-Workflow and use the spotlight-command mdfind, which is very fast in finding files with names containing a UID anywhere on my hard disk.

    open "`mdfind -name $query`"

    (where $query is the UID or any other part of a filename).

  • Thanks, @rhubarb. I'm new to shell scripting and wasn't aware of mdfind.

    I used find because I wanted to keep to standard Unix commands wherever possible, and to search the files themselves rather than a database which may be out of date (as locate and mdfind do). I'm guessing that Spotlight is pretty good at keeping its database up to date though, so maybe this isn't a practical problem for mdfind.

    To test speed, I cded into a directory of about 600 plain text files (inside a VeraCrypt volume):

    Testing mdfind:

    time mdfind 'kMDItemFSName = 202004150005*' -onlyin .
    ... 0.01s user 0.01s system 39% cpu 0.039 total

    Testing find:

    time find . -name '202004150001'
    ... 0.00s user 0.00s system 58% cpu 0.010 total

    Running the search on the whole volume, which contains about 39,000 files:

    mdfind: 0.01s user 0.01s system 9% cpu 0.169 total

    find: 0.03s user 0.17s system 98% cpu 0.196 total

    Running the search from / (that is, the whole of Macintosh HD):

    mdfind: 0.01s user 0.01s system 37% cpu 0.043 total

    find: 6.15s user 88.16s system 53% cpu 2:54.83 total

    find didn't have permission to search many directories and caused a number of permission request dialogues to pop up.

    So I infer that find may be faster for highly targeted searches, but as the number of files to be searched increases mdfind quickly catches up, and at some point between 39,000 files and the whole contents of my laptop, find becomes unusably slow.

    This StackExchange answer is useful in understanding the pros and cons.

  • Please ignore the test results above.

    I don't think I kept the number of matches to each search consistent at one, and the search string in the case of both find and mdfind should be sandwiched between asterisks (e.g. *202007221713*) for a fair comparison and to find a file or folder with the UID anywhere in its name.

    In summary:

    • The macro now uses mdfind because:

      • As above, mdfind is much faster than find except in the case of highly targeted searches. find can easily become uselessly slow.
      • I haven't found mdfind to miss a file. That Spotlight's database might be out of date doesn't seem to be a practical concern. Furthermore, this Stack Overflow answer asserts that any metadata attribute with FS in it is not stored in Spotlight's database at all. I haven't seen this corroborated, but searches on kMDItemDisplayName do seem to run faster than on kMDItemFSName.
      • I've decided to assign less importance to the portability of shell scripts given the context of the macro.
    • Other file systems (at least exFAT) and VeraCrypt volumes (even if formatted "Mac OS Extended") don't retain the metadata attribute kMDItemDisplayName. For this reason, the macro searches on kMDItemFSName, despite being slower.

    The macro now opens folders as well as files and has been renamed to reflect this. This is an updated direct link to the macro (you may have to right click and 'save link/target').

    time test results:

    In each case, a single file matches the search.

    Run from the root of a directory in a VeraCrypt volume containing about 620 text files:

    time mdfind "kMDItemFSName=*202007221713*" -onlyin .
    ... 0.01s user 0.01s system 36% cpu 0.041 total
    time find . -name "*202007221713*"
    ... 0.00s user 0.00s system 85% cpu 0.005 total

    Run from the root of a copy of that directory, outside of the VeraCrypt volume:

    • mdfind, searching on kMDItemFSName: 0.00s user 0.01s system 22% cpu 0.058 total
    • mdfind, searching on kMDItemDisplayName: 0.01s user 0.01s system 27% cpu 0.058 total
    • find: 0.00s user 0.00s system 87% cpu 0.005 total

    Run from the root of a VeraCrypt volume containing about 33,000 files:

    • mdfind, searching on kMDItemFSName: 0.00s user 0.01s system 9% cpu 0.136 total
    • find: 0.07s user 0.14s system 98% cpu 0.207 total (permission errors)

    Universal search, including mounted volumes (a partition, external HDD, other VeraCrypt volumes):

    time mdfind "kMDItemFSName=*202007221713*"
    ... 0.01s user 0.01s system 10% cpu 0.154 total
    time mdfind "kMDItemDisplayName=*202007221713*"          
    ... 0.00s user 0.01s system 14% cpu 0.096 total

    find: 12.60s user 92.72s system 67% cpu 2:36.92 total (numerous permission errors)

    Universal search, excluding mounted volumes:

    time mdfind "kMDItemFSName=*202007221713*" -onlyin /
    ...  0.01s user 0.01s system 25% cpu 0.061 to=tal
    time mdfind "kMDItemDisplayName=*202007221713*" -onlyin /
    ... 0.00s user 0.01s system 25% cpu 0.056 total
Sign In or Register to comment.