Stack Exchange

Digging Deeper: Mastering Spotlight in OS X

June 3, 2011 by . 2 comments

Spotlight is a great feature of OS X that many of its users love for being simple and fast. With a single click or keystroke you can search for files and applications on your Mac. Results are displayed instantaneously and often very useful.

Most of the users click the Spotlight button on the top right of your OS X menu bar or press Cmd-Space to open the Spotlight window. While this comes in handy for simple application launching or finding files you use on a daily basis, there is much more to Spotlight than this.

When our user @kjo asked how to find old unused files in OS X, he wanted to find files that had not been opened in a long time. Let’s see what Spotlight can do to help us here.

The Spotlight Search Window

If you press “Show All” in the list of results, or if you search with Alt-Cmd-Space, you are presented a Finder window with a search bar. It allows you to restrict the search to the current folder you are in and offers you to choose between searching for file contents or file names only.

Adding Search Parameters

But wait, there’s more! If you click the small + button right next to “Save”, you can add additional search parameters. Here is where it gets interesting. You can select the following fields by default:

  • File kind: Here you can select the kind of file you are looking for. This allows you to, for example, specifically search for PDF files only
  • Last opened date: This is the time the file was last opened/read
  • Last modified date: This is the time the file was last written and therefore changed
  • Created date: This is the time the file was initially created
  • Name: This is the file name only
  • Contents: These are the contents of the file itself, which is particularly helpful for text documents such as PDFs or Word files.

Clicking the + button again we can further refine the query, making it possible to find, for example, Excel files containing the word “budget” that were created last year. Or pictures that are named something like “kittens”, which you edited within the last week. Turns out we only have one:

Kittens search

Or, to address our problem of searching files not modified within a certain time period, we just look for files “Last modified” before a certain date. Here’s an example for really old files that haven’t been modified in a long time:

old files

Adding Boolean Conditions

It gets even better though. Sometimes it’s just not enough to use simple parameters. If you hold the alt key, you will see that the + button turned into an ellipsis (...).

Click this and you will be presented with a new bar that allows you to specifically combine conditions. You can now choose to refine results based on whether any, none or all of the following conditions are true.

In most cases, it is helpful to filter out results you don’t want. For example you could remove certain file name patterns or file kinds that you specifically don’t need. If you want to restrict results to certain dates, you have to be careful though: There seems to be a bug. As @Daniel Beck noted in his answer, the “Last opened/modified date” don’t always behave the way you would expect them to when used with boolean conditions. In fact, they are just plain useless for some files. A mitigation seems to be to combine both, as you can see in this example. If you have a simple query, it’s just better to use the variant above (using the “before” setting).

Saving Searches

Now that you’ve constructed awesome search queries, you can also save them using the “Save” button. You will then be prompted for a name. The most useful part of that is the possibility of including them in the Finder sidebar. Here you can link to all your favorite searches that you might need on a daily basis. Per default there are some searches included, like for files modified today, yesterday, or within the last week, but also for images, movies and documents. But feel free to extend them by defining your own advanced searches. If you use your Mac for both work and private files, then you can easily create search queries that give you a set of files to work with and switch between them.

Adding More Columns to Sort By

In its default setting, the Spotlight results window only allows you to sort files by their name, kind or last opened date. While this is useful in most cases, it would be great to have the same usual columns to sort by (e.g. file size or modified date). For example, when you want to delete the largest video files on your hard disk. We can’t change this through a simple setting, however there is a workaround.

Our user @NSGod found a way to include more columns. The full explanation can be found in his excellent answer. In order to include more columns, follow these steps:

  • Go to your home folder, and open Library/Preferences/com.apple.finder.plist. Preferably this is done with Property List Editor.app, which comes with Apple’s developer tools.
  • Here, navigate to SearchViewSettings > ListViewSettings > columns
  • You will find entries for all columns that can be shown, from “comments” to “version”. To activate each column individually, expand it and activate the “visible” checkbox.
  • Save the Property List file and relaunch the Finder by holding alt and right-clicking the Finder icon in the dock. Then select “Relaunch”.

For the command-line junkies, there’s also a shortcut found by Daniel Beck. Open up a Terminal. Then, to enable the “size” column, copy the following command to it and make sure you paste it as one line.

/usr/libexec/PlistBuddy -c "Set :SearchViewSettings:ListViewSettings:columns:size:visible true" Library/Preferences/com.apple.Finder.plist
You can also change the size in this command to another column you want to include, for example comment, dateCreated, dateModified, label and version. Now you can sort by one of these columns, as you would expect from a normal Finder window.

Using the Command Line and mdfind

We wouldn’t be Super Users if we didn’t love the command line so much. As OS X is based on Unix, we have several tools at hand that allow us to script various actions based on files. Apple was so nice to offer us a command line version of Spotlight’s search functionality. It can be invoked as mdfind.

In the very basic version, it does the same as a normal search: Display result files in a list. Take this example:

charon:~ werner$ mdfind kittens
/Users/werner/Desktop/kittens.jpg
/Users/werner/Photos/another-picture-of-kittens.jpg
Neat – now we can use these results in any other script. A very basic solution would be to export the result as a list of file paths:
mdfind kittens > list_of_kittens.txt
But you can also pipe the file names to xargs and let the Unix magic happen. Note that mdfind also has the -0 argument for passing file names with spaces, so that you can run something really basic like:
mdfind something -0 | xargs -0 basename
Or copy the files somewhere
mdfind something -0 | xargs -0 -I {} cp {} /some/folder
I’m sure that there are plenty of more useful things to do with these options. Now let’s look into how we can refine those search results.

Basic Arguments

mdfind is of course as powerful as its GUI counterpart. First of all, there’s the -onlyin <folder> argument. You can use it to specify the folder in which Spotlight should search. Normally it would crawl through the whole hard drive, but sometimes you might only want to search in your home folder. The home folder is in /Users/your-username/, but it can be abbreviated as ~. So searching in the home folder would be very simple:

mdfind -onlyin ~ "Some Text"
Such a query would do the same as a normal Spotlight search: Look for the string you entered both in file names and the file content. Sometimes you might only want to search for filenames. The -name <name> argument is there for that:
mdfind -onlyin ~ -name some-file.txt
Of course, there’s more: You can flavor the queries with as many arguments as you want. Such arguments always consist of an attribute and value pair. Let’s take two examples:
mdfind -onlyin ~ 'kMDItemTextContent == "Where was that text again?"'
mdfind -onlyin ~ 'kMDItemLastUsedDate <= $time.today(-5)'
Let’s break it apart: kMDItemTextContent and kMDItemLastUsedDate are one of many attributes you can use for queries. Here is a full list of attributes Spotlight keeps for you. Just take a look at them. There’s probably one for every use case. These include all of the attributes we mentioned above, but also a lot more.

How do you know which attributes a file has? You can easily check the metadata attributes of a file with the built-in mdls command. For example, let’s see the output of a video file:

mdls video.mov
You will get a large list of attributes, including the duration of the video, the codecs used, the bit rate, and even the pixel width and height are stored.

Most of the time we compare attributes to strings that we specify. In our example above, "Where was that text again?" is a simple string that we searched against. If you want to use quotation marks within the search string, make sure to escape them with before (e.g. "). Normally, the comparison between strings is case sensitive, which is not always preferable. You can also modify the string to be treated as case insensitive, which mostly leads to better results. Do that by appending c to it, for example like this:

mdfind -onlyin ~ 'kMDItemTextContent == "Where was that text again?"c'

Query Operators and Combined Arguments

In our examples above, we used two different operators, namely == and <=. There are obviously more and you can easily guess what they mean.

  • == means “equal”, != means “not equal”
  • < and > mean “less” or “more than”
  • <= and >= mean “less than or equal” or “more than or equal”

What if you want to combine multiple arguments? Like we did in the Finder window, we could combine arguments with && and ||, meaning “and” and “or” respectively. That way you can restrict or broaden your results. Let’s look at an example:

mdfind -onlyin ~ 'kMDItemKind == "QuickTime movie" && kMDItemPixelHeight >= 720'
mdfind -onlyin ~ '(kMDItemKind == "QuickTime movie" || kMDItemKind == "MPEG-4 movie") && kMDItemPixelHeight >= 720'
The first one searches for videos in the QuickTime format that are in HD resolution. The second one also includes MPEG-4 movies. Just group arguments with parentheses.

Using Dates and Other Tricks

In one of our examples above, we used $time.today(-5). What does it mean, exactly? As you can guess, $time.today() gives us the current day. Of course, there are more: You can also use .yesterday(), .this_week(), .this_month() and this_year(). What’s even better is that you can shift these dates by placing numbers into the parentheses.

That’s what we used in the example above. $time.today(-5) means: “Five days ago”. The same works for the others too. $time.this_year(-5) means “Five years ago”. Now just use <= and >= to compare dates in order to get files that for example have been modified before or after a certain date.

Now there are things we could not cover here in full length. If you want a detailed reference, you can take a look at it on Apple’s Developer site. Also check out the manpage of mdfind by calling man mdfind.

Filed under Software WTFriday

2 Comments

Subscribe to comments with RSS.

  • Kyle Cronin says:

    This is a great article. I touched on a few tips for Spotlight in Ask Different Podcast #3, but this is a lot more comprehensive. Well done.

  • [...] In the series of digging deeper within our files, we’ve had Spotlight and mdfind on Mac OS X. Now we’re back with a Windows counter-part article; where we will outline Windows Search and [...]

  • Leave a comment

    Log in
    with Stack Exchange
    or