Skip to content

Instantly share code, notes, and snippets.

@cwalston
Last active July 31, 2024 19:23
Show Gist options
  • Save cwalston/7425403 to your computer and use it in GitHub Desktop.
Save cwalston/7425403 to your computer and use it in GitHub Desktop.
! (C) 2013 Charles Alston.
USING: accessors arrays byte-arrays fry google.search io
io.encodings.utf8 io.launcher kernel locals make namespaces
sequences splitting strings unicode.categories vectors ;
FROM: webbrowser => open-file open-url ;
IN: spotlight
! *** searching on os x via spotlight metadata index, & managing indexing from factor ***
! *** mac os x 10.6.8 & later: implementing mdfind, mdls, mdutil, mdimport ***
! mdfind, mdls, mdutil, mdimport take a query on the stack
! & return a sequence of result strings
! -----
! TO DO:
! -need to test sudo-mdutil; intercept auth prompt
! -work out API call to MDSchemaCopyAllAttributes()
! -handle case-sensitivity properly (OS X)
! -test composing variant shell command constructions,
! i.e., those which do or don't need spaces, parens,
! single quotes, etc. (work through examples at end of file)
! -access o.e.d & calculator through spotlight
! -emit some sort of 'not-found' msg for unsuccessful search
! -trap errors! ...
! -----
SYMBOL: search-vec
: default-search-vec ( -- vector ) { "-onlyin" "/" } >vector ;
: search-vec! ( -- ) search-vec [ default-search-vec ] initialize ;
: get-search-vec ( -- vector ) search-vec! search-vec get ;
: reset-search-vec ( -- ) default-search-vec search-vec set ;
! change the search path
:: new-search-path ( my-path -- )
reset-search-vec
"/" search-vec get remove! my-path suffix! drop ;
! *********************** mdfind ***********************
! Usage: mdfind [-live] [-count] [-onlyin directory] [-name fileName | -s smartFolderName | query]
! list the files matching the query
! query can be an expression or a sequence of words
! -live Query should stay active
! -count Query only reports matching items count
! -onlyin <dir> Search only within given directory
! -name <name> Search on file name only
! -s <name> Show contents of smart folder <name>
! -0 Use NUL (``\0'') as a path separator, for use with xargs -0.
! example: mdfind image
! example: mdfind -onlyin ~ image
! example: mdfind -name stdlib.h
! example: mdfind "kMDItemAuthor == '*MyFavoriteAuthor*'"
! example: mdfind -live MyFavoriteAuthor
! -------
! example queries (some return faster than others):
! *** Return all files that have been modified today:
! "date:today" mdfind
! *** Return all files that have been modified in the last 3 days:
! "kMDItemFSContentChangeDate >= $time.today (-3)" mdfind
! *** filename with spaces, e.g.,
! "Finding Joy in Combinators.pdf" "kMDItemFSName" by-attribute mdfind
! *** filename without spaces , e.g.,
! "libfactor.dylib" mdfind
! *** phrase with spaces, e.g.,
! "Building Factor from source" mdfind
! *** phrase or term without spaces, e.g.,
! "call-effect-unsafe" mdfind
! "metadata" mdfind
! *** terms in a document:
! "Document cocoa.messages selector" mdfind
! *** all documents:
! "Document" mdfind - (long wait if there are lots).
! *** "pdf date:yesterday" mdfind
! *** "Dylan" "kMDItemComposer" by-attribute mdfind
! *** others, as per metadata attribute (see below), e.g.,
! "com.microsoft.word.doc" "kMDItemContentType" by-attribute mdfind
! -------
:: by-attribute ( item-name attr-name -- string )
attr-name " == " append
item-name "'" "'" surround append ;
:: <md-command> ( query cmd -- array ) ! 3 elems- cmd, path, query
get-search-vec query suffix cmd prefix ;
! once a command is built, this does the work
: utf8-stream-lines ( command -- seq )
utf8 [ lines ] with-process-reader ;
: mdfind ( query -- results )
"mdfind" <md-command> ! ( -- array )
utf8-stream-lines ;
! *********************** mdls ***********************
! *** getting Uniform Type Identifiers and
! other Metadata of a Given File ***
! example:
! "/Users/cwalston/factor/basis/ascii/ascii.factor" mdls
: mdls ( absfilepath -- seq )
"mdls" 1vector swap suffix! utf8-stream-lines ;
! *********************** mdutil ***********************
! *** Re-indexing Spotlight ***
! ➜ ~ git:(master) ✗ mdutil
! Usage: mdutil -pEsa -i (on|off) volume ...
! Utility to manage Spotlight indexes.
! -p Publish metadata.
! -i (on|off) Turn indexing on or off.
! -E Erase and rebuild index.
! -s Print indexing status.
! -a Apply command to all volumes.
! -v Display verbose information.
! NOTE: Run as owner for network homes, otherwise run as root.
! ➜ ~ git:(master) ✗
! "sudo mdutil -E /
! This will re-index every mounted volume on the Mac, including hard
! drives, disk images, external drives, etc. Specific drives can be chosen
! by pointing to them in /Volumes/, to only rebuild the primary Macintosh HD:
! sudo mdutil -E /Volumes/Macintosh\ HD/
! To re-index an external drive named “External” the command would be:
! sudo mdutil -E /Volumes/External/
! Use of the mdutil command will spin up mds and mdworker
! processes as Spotlight goes to work."
! example:
! "/Volumes/Jurassic Grad - Spare Change" md-re-index
! returned: ( -- { "/Volumes/Jurassic Grad - Spare Change:" "\tIndexing enabled. " } )
! *** N.B. -
! this starts indexing as intended, but spotlight often has the irritating habit
! of indexing 'til the cows come home! i succeeded in spanking that behavior to a halt
! by quitting the mds system process in activity monitor.
! TIP: google "Spotless", a well-recommended shareware app that knows how to manage the beast.
:: (mdutil) ( flags on|off volume root/owner -- seq )
root/owner 1vector "-" flags append suffix!
"-i" suffix! on|off suffix! volume suffix!
utf8-stream-lines ;
: mdutil ( flags on|off volume -- seq )
"mdutil" (mdutil) ;
! NEEDS TESTING - how to intercept authentication prompt?
: sudo-mdutil ( flags on|off volume -- seq )
"sudo mdutil" (mdutil) ;
! *********************** mdimport ***********************
! *** Individually Re-indexing Selected Files ***
! ➜ ~ git:(master) ✗ mdimport
! Usage: mdimport [OPTION] path
! -d debugLevel Integer between 1-4
! -g plugin Import files using the listed plugin, rather than the system installed plugins.
! -p Print out performance information gathered during the run
! -A Print out the list of all of the attributes and exit
! -X Print out the schema file and exit
! -L Print out the List of plugins that we are going to use and exit
! -r Ask the server to reimport files for UTIs claimed by the listed plugin.
! -n Don't send the imported attributes to the data store.
! ➜ ~ git:(master) ✗
! "In rare cases, Spotlight can miss a file during index, so rather than
! re-index an entire drive you can also manually add an individual file to
! the search index with the mdimport command:
! mdimport /path/to/file
! The mdimport command can be used on directories as well."
! a simple, no options example - touch file & retrieve its MetaData:
! "/Users/cwalston/factor/mdimport-test" [ touch-file ] keep [ "" mdimport ] keep mdls
! or just:
! "/Users/cwalston/factor/mdimport-test" "-p" mdimport
:: mdimport ( abspath options -- seq )
"mdimport" 1vector options dup empty? not ! ( -- vector opt ? )
[ suffix! ] [ drop ] if abspath suffix!
utf8-stream-lines ;
! **** ANCILLARY INFO, MOTLEY EXAMPLES ***
! instruct mds (MetaDataServer) to clear out the metadata cache and rebuild from scratch,
! using this command run from Terminal: sudo mdutil -avE
!
! *** AT COMMAND LINE ON OS X 10.6.8 ***
! mdfind USAGE:
! ➜ ~ git:(master) ✗ mdfind
! mdfind: no query specified.
! Usage: mdfind [-live] [-count] [-onlyin directory] [-name fileName | -s smartFolderName | query]
! list the files matching the query
! query can be an expression or a sequence of words
! -live Query should stay active
! -count Query only reports matching items count
! -onlyin <dir> Search only within given directory
! -name <name> Search on file name only
! -s <name> Show contents of smart folder <name>
! -0 Use NUL (``\0'') as a path separator, for use with xargs -0.
! ***NOT AVAILABLE ON 10.6.8??? --
! -literal Force the provided query string to be taken as a literal query
! string, without interpretation.
!
! -interpret Force the provided query string to be interpreted as if the user
! had typed the string into the Spotlight menu.
! For example, the string "search" would produce the following
! query string:
! (* = search* cdw || kMDItemTextContent = search* cdw)
!
!
! example: mdfind image (--OR mdfind "mdfind USAGE:" FOR PHRASES)
! example: mdfind -onlyin ~ image
! example: mdfind -name stdlib.h
! example: mdfind "kMDItemAuthor == '*MyFavoriteAuthor*'" (--OR e.g., mdfind 'kMDItemAuthor == "Henry David Thoreau"' )
! example: mdfind -live MyFavoriteAuthor
!
! ➜ ~ git:(master) ✗
! ***************** mdfind command line examples *****************
! name:file.txt
! kind:"jpeg image" (kind:jpg or *.jpg doesn't work)
! date:today
! date:"this week" (date:week doesn't work)
! modified:12/31/11
! kind:video AND size:<100000
! created:12/1/11-12/31/11
!
! Spotlight Keywords-
! These can be included in the query expression to limit the type
! of documents returned:
!
! Applications kind:application, kind:applications, kind:app
! Audio/Music kind:audio, kind:music
! Bookmarks kind:bookmark, kind:bookmarks
! Contacts kind:contact, kind:contacts
! Email kind:email, kind:emails, kind:mail message,
! kind:mail messages
! Folders kind:folder, kind:folders
! Fonts kind:font, kind:fonts
! iCal Events kind:event, kind:events
! iCal To Dos kind:todo, kind:todos, kind:to do, kind:to dos
! Images kind:image, kind:images
! Movies kind:movie, kind:movies
! PDF kind:pdf, kind:pdfs
! Preferences kind:system preferences, kind:preferences
! Presentations kind:presentations, kind:presentation
!
! Date Keywords-
! These can be included in the query expression to limit the age
! of documents returned:
!
! date:today $time.today()
! date:yesterday .yesterday()
! date:this week .this_week()
! date:this month .this_month()
! date:this year .this_year()
! date:tomorrow .tomorrow()
! date:next month .next_month()
! date:next week .next_week()
! date:next year .next_year()
!
! Boolean Operators-
! By default mdfind will AND together elements of the query string.
!
! | (OR) To return items that match either word, use the pipe character:
! stringA|stringB
! - (NOT) To exclude documents that match a string -string
! == “equal”
! = “not equal”
! < and > “less” or “more than”
! <= and >= “less than or equal” or “more than or equal”
!
! lenin|trotsky will find documents mentioning either Lenin or Trotsky
! lenin(-stalin) will find documents mentioning Lenin, but not, thankfully, Stalin
! lenin|trotsky(-stalin) will find documents mentioning either Lenin or Trotsky, but not Stalin
!
! Returns all files with any metadata attribute value matching the string "image":
! $ mdfind image
!
! Return all files that contain "Len Deighton" in the kMDItemAuthor metadata attribute:
! $ mdfind "kMDItemAuthor == '*Len Deighton*'"
!
! Return all files with any metadata attribute value matching the string
! "skateboard". The find continues to run after gathering the initial results,
! providing a count of the number of files that match the query.
! $ mdfind -live skateboard
!
! Return all Microsoft.Word document files:
! $ mdfind "kMDItemContentType == 'com.microsoft.word.doc'"
!
! Return files where the composer name includes 'Eno'
! (non case sensitive search):
! $ mdfind 'kMDItemComposer = "*ENO*"c'
!
! Return all image files matching the words 'maude' and 'paris':
! $ mdfind "kind:images maude paris"
!
! Return all image files last edited yesterday:
! $ mdfind "kind:image date:yesterday"
!
! Return all files in the users home folder (~) that have been modified in the
! last 3 days:
! $ mdfind -onlyin ~ 'kMDItemFSContentChangeDate >= $time.today (-3)'
!
! mdfind '"exact phrase"'
!
! mdfind kMDItemFSName=\*.scpt
! mdfind 'kMDItemFSName=*' -onlyin . # doesn't include hidden files
! mdfind kMDItemFSName=.DS_Store -0 | xargs -0 rm
! mdfind -0 -onlyin ~/Music 'kMDItemFSName=*.mp3&&kMDItemAudioBitRate<=192000' | xargs -0 mdls -name kMDItemAlbum | sort | uniq
!
! mdfind kMDItemContentType=com.apple.application-bundle -onlyin /usr/local
! mdfind kMDItemContentTypeTree=com.apple.bundle
! mdfind kMDItemContentTypeTree=public.movie
!
! mdfind 'kMDItemTextContent="*expose*"cd' # ignore case and diacritics
! mdfind kMDItemTextContent=*LSUIElement* -onlyin ~/Projects/applepdfs/
!
! mdfind 'kMDItemFSSize>=5000&&kMDItemFSSize<=5005'
!
! mdfind 'kMDItemFSContentChangeDate>=$time.iso(2012-04-13T13:44Z)'
!
! mdfind 'kMDItemFSCreationDate>=$time.now(-3600)'
!
! mdfind 'kMDItemKind=*movie&&kMDItemPixelHeight>=720'
!
! mdfind 'kMDItemFSInvisible=1||kMDItemFSInvisible=0' -onlyin . # includes hidden files
!
! mdfind 'kMDItemURL=*web.archive.org*page*' -onlyin ~/Library/Caches/Metadata/Safari/History
!
! mdfind 'kMDItemFSSize>=1e8&&kMDItemContentTypeTree=public.directory'
!
! mdfind kind:pdf
!
! mdfind 'kMDItemFSLabel>0' # items with color labels
!
! mdfind -onlyin / # like -onlyin /Volumes/Macintosh\ HD
!
! mdfind "$(PlistBuddy -c 'Print RawQuery' test.savedSearch)"
!
! sudo mdfind com_apple_backup_excludeItem=com.apple.backupd
!
! *** N.B. - SOME EXAMPLES © Copyright SS64.com 1999-2013 Some rights reserved ***
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment