

{"id":13016,"date":"2021-04-13T08:59:26","date_gmt":"2021-04-13T13:59:26","guid":{"rendered":"https:\/\/rud.is\/b\/?p=13016"},"modified":"2021-04-13T08:59:26","modified_gmt":"2021-04-13T13:59:26","slug":"quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r","status":"publish","type":"post","link":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/","title":{"rendered":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R"},"content":{"rendered":"<p>(reminder: Quick Hits have minimal explanatory blathering, but I can elaborate on anything if folks submit a comment).<\/p>\n<p>I&#8217;m playing around with Screen Time on xOS again and noticed <code>mdls<\/code> (macOS command line utility for getting file metadata) has a <code>-plist<\/code> option (it probably has for a while &amp; I just never noticed it). I further noticed there&#8217;s a <code>kMDItemExecutableArchitectures<\/code> key (which, too, may have been &#8220;a thing&#8221; before as well). Having application metadata handy for the utility functions I&#8217;m putting together for Rmd-based Screen Time reports would be handy, so I threw together some quick code to show how to work with it in R.<\/p>\n<p>Running <code>mdls -plist \/some\/file.plist ...path-to-apps...<\/code> will generate a giant property list file with all metadata for all the apps specified. It&#8217;s a <em>wicked fast<\/em> command even when grabbing and outputting metadata for all apps on a system.<\/p>\n<p>Each entry looks like this:<\/p>\n<pre><code class=\"language-xml\">&lt;dict&gt;\n    &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\n    &lt;string&gt;RStudio \u2014 tycho.app&lt;\/string&gt;\n    &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\n    &lt;array&gt;\n      &lt;string&gt;RStudio \u2014 tycho.app&lt;\/string&gt;\n    &lt;\/array&gt;\n    &lt;key&gt;kMDItemCFBundleIdentifier&lt;\/key&gt;\n    &lt;string&gt;com.RStudio_\u2014_tycho&lt;\/string&gt;\n    &lt;key&gt;kMDItemContentCreationDate&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T17:56:46Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemContentCreationDate_Ranking&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T00:00:00Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemContentModificationDate&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T17:56:46Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemContentModificationDate_Ranking&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T00:00:00Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemContentType&lt;\/key&gt;\n    &lt;string&gt;com.apple.application-bundle&lt;\/string&gt;\n    &lt;key&gt;kMDItemContentTypeTree&lt;\/key&gt;\n    &lt;array&gt;\n      &lt;string&gt;com.apple.application-bundle&lt;\/string&gt;\n      &lt;string&gt;com.apple.application&lt;\/string&gt;\n      &lt;string&gt;public.executable&lt;\/string&gt;\n      &lt;string&gt;com.apple.localizable-name-bundle&lt;\/string&gt;\n      &lt;string&gt;com.apple.bundle&lt;\/string&gt;\n      &lt;string&gt;public.directory&lt;\/string&gt;\n      &lt;string&gt;public.item&lt;\/string&gt;\n      &lt;string&gt;com.apple.package&lt;\/string&gt;\n    &lt;\/array&gt;\n    &lt;key&gt;kMDItemCopyright&lt;\/key&gt;\n    &lt;string&gt;Copyright \u00a9 2017-2020 BZG Inc. All rights reserved.&lt;\/string&gt;\n    &lt;key&gt;kMDItemDateAdded&lt;\/key&gt;\n    &lt;date&gt;2021-04-09T18:29:52Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemDateAdded_Ranking&lt;\/key&gt;\n    &lt;date&gt;2021-04-09T00:00:00Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemDisplayName&lt;\/key&gt;\n    &lt;string&gt;RStudio \u2014 tycho.app&lt;\/string&gt;\n    &lt;key&gt;kMDItemDocumentIdentifier&lt;\/key&gt;\n    &lt;integer&gt;0&lt;\/integer&gt;\n    &lt;key&gt;kMDItemExecutableArchitectures&lt;\/key&gt;\n    &lt;array&gt;\n      &lt;string&gt;x86_64&lt;\/string&gt;\n    &lt;\/array&gt;\n    &lt;key&gt;kMDItemFSContentChangeDate&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T17:56:46Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemFSCreationDate&lt;\/key&gt;\n    &lt;date&gt;2021-01-31T17:56:46Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemFSCreatorCode&lt;\/key&gt;\n    &lt;integer&gt;0&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSFinderFlags&lt;\/key&gt;\n    &lt;integer&gt;0&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSInvisible&lt;\/key&gt;\n    &lt;false\/&gt;\n    &lt;key&gt;kMDItemFSIsExtensionHidden&lt;\/key&gt;\n    &lt;true\/&gt;\n    &lt;key&gt;kMDItemFSLabel&lt;\/key&gt;\n    &lt;integer&gt;0&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSName&lt;\/key&gt;\n    &lt;string&gt;RStudio \u2014 tycho.app&lt;\/string&gt;\n    &lt;key&gt;kMDItemFSNodeCount&lt;\/key&gt;\n    &lt;integer&gt;1&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSOwnerGroupID&lt;\/key&gt;\n    &lt;integer&gt;20&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSOwnerUserID&lt;\/key&gt;\n    &lt;integer&gt;501&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSSize&lt;\/key&gt;\n    &lt;integer&gt;37451395&lt;\/integer&gt;\n    &lt;key&gt;kMDItemFSTypeCode&lt;\/key&gt;\n    &lt;integer&gt;0&lt;\/integer&gt;\n    &lt;key&gt;kMDItemInterestingDate_Ranking&lt;\/key&gt;\n    &lt;date&gt;2021-04-13T00:00:00Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemKind&lt;\/key&gt;\n    &lt;string&gt;Application&lt;\/string&gt;\n    &lt;key&gt;kMDItemLastUsedDate&lt;\/key&gt;\n    &lt;date&gt;2021-04-13T12:47:12Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemLastUsedDate_Ranking&lt;\/key&gt;\n    &lt;date&gt;2021-04-13T00:00:00Z&lt;\/date&gt;\n    &lt;key&gt;kMDItemLogicalSize&lt;\/key&gt;\n    &lt;integer&gt;37451395&lt;\/integer&gt;\n    &lt;key&gt;kMDItemPhysicalSize&lt;\/key&gt;\n    &lt;integer&gt;38092800&lt;\/integer&gt;\n    &lt;key&gt;kMDItemUseCount&lt;\/key&gt;\n    &lt;integer&gt;20&lt;\/integer&gt;\n    &lt;key&gt;kMDItemUsedDates&lt;\/key&gt;\n    &lt;array&gt;\n      &lt;date&gt;2021-03-15T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-17T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-18T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-19T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-22T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-25T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-03-30T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-01T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-03T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-05T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-07T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-08T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-12T04:00:00Z&lt;\/date&gt;\n      &lt;date&gt;2021-04-13T04:00:00Z&lt;\/date&gt;\n    &lt;\/array&gt;\n    &lt;key&gt;kMDItemVersion&lt;\/key&gt;\n    &lt;string&gt;4.0.1&lt;\/string&gt;\n  &lt;\/dict&gt;\n<\/code><\/pre>\n<p>We can get all the metadata for all installed apps in R via:<\/p>\n<pre><code class=\"language-r\">library(sys)\nlibrary(xml2)\nlibrary(tidyverse)\n\n# get full paths to all the apps\nlist.files(\n  c(\"\/Applications\", \"\/System\/Library\/CoreServices\", \"\/Applications\/Utilities\", \"\/System\/Applications\"), \n  pattern = \"\\\\.app$\", \n  full.names = TRUE\n) -&gt; apps\n\n# generate a giant property list with all the app attributres\ntf &lt;- tempfile(fileext = \".plist\")\nsys::exec_internal(\"mdls\", c(\"-plist\", tf, apps))\n<\/code><\/pre>\n<p>Unfortunately, some companies \u2014 COUGH Logitech COUGH \u2014 stick illegal entities in some values, so we have to take care of those (I used <code>xmllint<\/code> to see which one(s) were bad):<\/p>\n<pre><code class=\"language-r\"># read it in and clean up CDATA error (Logitech has a bad value in one field)\nfil &lt;- readr::read_file_raw(tf)\nfil[fil == as.raw(0x03)] &lt;- charToRaw(\" \")\n<\/code><\/pre>\n<p>Now, we can read in the XML without errors:<\/p>\n<pre><code class=\"language-r\"># now parse it and get the top of each app entry\napplist &lt;- xml2::read_xml(fil)\n(applist &lt;- xml_find_all(applist, \"\/\/array\/dict\"))\n## {xml_nodeset (196)}\n##  [1] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;1Blocker (Old).app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n ...\n##  [2] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;1Password 7.app&lt;\/string&gt;\\n  &lt;key&gt;_kMDItemEngagementData&lt;\/key&gt;\\n   ...\n##  [3] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Adblock Plus.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n   ...\n##  [4] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;AdBlock.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;arra ...\n##  [5] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;AdGuard for Safari.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/ke ...\n##  [6] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Agenda.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;array ...\n##  [7] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Alfred 4.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;arr ...\n##  [8] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Android File Transfer.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt; ...\n##  [9] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Asset Catalog Creator Pro.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNa ...\n## [10] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Awsaml.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;array ...\n## [11] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Boop.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;array&gt;\\ ...\n## [12] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Buffer.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;array ...\n## [13] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Burp Suite Community Edition.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternat ...\n## [14] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Camera Settings.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\ ...\n## [15] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Cisco Webex Meetings.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/ ...\n## [16] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Claquette.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;ar ...\n## [17] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Discord.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;arra ...\n## [18] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Elgato Control Center.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt; ...\n## [19] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;F5 Weather.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt;a ...\n## [20] &lt;dict&gt;\\n  &lt;key&gt;_kMDItemDisplayNameWithExtensions&lt;\/key&gt;\\n  &lt;string&gt;Fantastical.app&lt;\/string&gt;\\n  &lt;key&gt;kMDItemAlternateNames&lt;\/key&gt;\\n  &lt; ...\n## ...\n<\/code><\/pre>\n<p>I really dislike property lists as I&#8217;m not a fan of position-dependent records in XML files. To get values for keys, we have to find the key, then go to the next sibling, figure out its type, and handle it accordingly. This is a verbose enough process to warrant creating a small helper function:<\/p>\n<pre><code class=\"language-r\"># helper function to retrieve the values for a given key\nkval &lt;- function(doc, key) {\n\n  val &lt;- xml_find_first(doc, sprintf(\".\/\/key[contains(., '%s')]\/following-sibling::*\", key))\n\n  switch(\n    unique(na.omit(xml_name(val))),\n    \"array\" = as_list(val) |&gt; map(unlist, use.names = FALSE) |&gt; map(unique),\n    \"integer\" = xml_integer(val),\n    \"true\" = TRUE,\n    \"false\" = FALSE,\n    \"string\" = xml_text(val, trim = TRUE)\n  )\n\n}\n<\/code><\/pre>\n<p>This is nowhere near as robust as <code>XML::readKeyValueDB()<\/code> but it doesn&#8217;t have to be for this particular use case.<\/p>\n<p>We can build up a data frame with certain fields (I wanted to know how many apps still aren&#8217;t Universal):<\/p>\n<pre><code class=\"language-r\">tibble(\n  category = kval(applist, \"kMDItemAppStoreCategory\"),\n  bundle_id = kval(applist, \"kMDItemCFBundleIdentifier\"),\n  display_name = kval(applist, \"kMDItemDisplayName\"),\n  arch = kval(applist, \"kMDItemExecutableArchitectures\"),\n) |&gt; \n  print() -&gt; app_info\n## # A tibble: 196 x 4\n##    category        bundle_id                            display_name                  arch     \n##    &lt;chr&gt;           &lt;chr&gt;                                &lt;chr&gt;                         &lt;list&gt;   \n##  1 Productivity    com.khanov.BlockerMac                1Blocker (Old).app            &lt;chr [2]&gt;\n##  2 Productivity    com.agilebits.onepassword7           1Password 7.app               &lt;chr [2]&gt;\n##  3 Productivity    org.adblockplus.adblockplussafarimac Adblock Plus.app              &lt;chr [2]&gt;\n##  4 Productivity    com.betafish.adblock-mac             AdBlock.app                   &lt;chr [1]&gt;\n##  5 Utilities       com.adguard.safari.AdGuard           AdGuard for Safari.app        &lt;chr [1]&gt;\n##  6 Productivity    com.momenta.agenda.macos             Agenda.app                    &lt;chr [2]&gt;\n##  7 Productivity    com.runningwithcrayons.Alfred        Alfred 4.app                  &lt;chr [2]&gt;\n##  8 NA              com.google.android.mtpviewer         Android File Transfer.app     &lt;chr [1]&gt;\n##  9 Developer Tools com.bridgetech.asset-catalog         Asset Catalog Creator Pro.app &lt;chr [2]&gt;\n## 10 Developer Tools com.rapid7.awsaml                    Awsaml.app                    &lt;chr [1]&gt;\n## # \u2026 with 186 more rows\n<\/code><\/pre>\n<p>Finally, we can expand the <code>arch<\/code> column and see how many apps support Apple Silicon:<\/p>\n<pre><code class=\"language-r\">app_info |&gt; \n  unnest(arch) |&gt; \n  spread(arch, arch) |&gt; \n  mutate_at(\n    vars(arm64, x86_64),\n    ~!is.na(.x)\n  ) |&gt; \n  count(arm64)\n## # A tibble: 2 x 2\n##   arm64     n\n##   &lt;lgl&gt; &lt;int&gt;\n## 1 FALSE    33\n## 2 TRUE    163\n<\/code><\/pre>\n<p>Alas, there are still some stragglers stuck in Rosetta 2.<\/p>\n<h3>FIN<\/h3>\n<p>Drop comments if anything requires more blathering and have some fun with your macOS filesystem!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>(reminder: Quick Hits have minimal explanatory blathering, but I can elaborate on anything if folks submit a comment). I&#8217;m playing around with Screen Time on xOS again and noticed mdls (macOS command line utility for getting file metadata) has a -plist option (it probably has for a while &amp; I just never noticed it). I [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_memberships_contains_paid_content":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[780,91],"tags":[],"class_list":["post-13016","post","type-post","status-publish","format-standard","hentry","category-macos","category-r"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is\" \/>\n<meta property=\"og:description\" content=\"(reminder: Quick Hits have minimal explanatory blathering, but I can elaborate on anything if folks submit a comment). I&#8217;m playing around with Screen Time on xOS again and noticed mdls (macOS command line utility for getting file metadata) has a -plist option (it probably has for a while &amp; I just never noticed it). I [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/\" \/>\n<meta property=\"og:site_name\" content=\"rud.is\" \/>\n<meta property=\"article:published_time\" content=\"2021-04-13T13:59:26+00:00\" \/>\n<meta name=\"author\" content=\"hrbrmstr\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"hrbrmstr\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/\"},\"author\":{\"name\":\"hrbrmstr\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"headline\":\"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R\",\"datePublished\":\"2021-04-13T13:59:26+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/\"},\"wordCount\":342,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"articleSection\":[\"macOS\",\"R\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/\",\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/\",\"name\":\"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#website\"},\"datePublished\":\"2021-04-13T13:59:26+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/2021\\\/04\\\/13\\\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/rud.is\\\/b\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#website\",\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/\",\"name\":\"rud.is\",\"description\":\"&quot;In God we trust. All others must bring data&quot;\",\"publisher\":{\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/rud.is\\\/b\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/rud.is\\\/b\\\/#\\\/schema\\\/person\\\/d7cb7487ab0527447f7fda5c423ff886\",\"name\":\"hrbrmstr\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"url\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"contentUrl\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\",\"width\":460,\"height\":460,\"caption\":\"hrbrmstr\"},\"logo\":{\"@id\":\"https:\\\/\\\/i0.wp.com\\\/rud.is\\\/b\\\/wp-content\\\/uploads\\\/2023\\\/10\\\/ukr-shield.png?fit=460%2C460&ssl=1\"},\"description\":\"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7\",\"sameAs\":[\"http:\\\/\\\/rud.is\"],\"url\":\"https:\\\/\\\/rud.is\\\/b\\\/author\\\/hrbrmstr\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/","og_locale":"en_US","og_type":"article","og_title":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is","og_description":"(reminder: Quick Hits have minimal explanatory blathering, but I can elaborate on anything if folks submit a comment). I&#8217;m playing around with Screen Time on xOS again and noticed mdls (macOS command line utility for getting file metadata) has a -plist option (it probably has for a while &amp; I just never noticed it). I [&hellip;]","og_url":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/","og_site_name":"rud.is","article_published_time":"2021-04-13T13:59:26+00:00","author":"hrbrmstr","twitter_card":"summary_large_image","twitter_misc":{"Written by":"hrbrmstr","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/#article","isPartOf":{"@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/"},"author":{"name":"hrbrmstr","@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"headline":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R","datePublished":"2021-04-13T13:59:26+00:00","mainEntityOfPage":{"@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/"},"wordCount":342,"commentCount":2,"publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"articleSection":["macOS","R"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/","url":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/","name":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R - rud.is","isPartOf":{"@id":"https:\/\/rud.is\/b\/#website"},"datePublished":"2021-04-13T13:59:26+00:00","breadcrumb":{"@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/rud.is\/b\/2021\/04\/13\/quick-hit-processing-macos-application-metadata-weirdly-fast-with-mdls-and-r\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/rud.is\/b\/"},{"@type":"ListItem","position":2,"name":"Quick Hit: Processing macOS Application Metadata Weirdly Fast with mdls and R"}]},{"@type":"WebSite","@id":"https:\/\/rud.is\/b\/#website","url":"https:\/\/rud.is\/b\/","name":"rud.is","description":"&quot;In God we trust. All others must bring data&quot;","publisher":{"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/rud.is\/b\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/rud.is\/b\/#\/schema\/person\/d7cb7487ab0527447f7fda5c423ff886","name":"hrbrmstr","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","url":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","contentUrl":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1","width":460,"height":460,"caption":"hrbrmstr"},"logo":{"@id":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2023\/10\/ukr-shield.png?fit=460%2C460&ssl=1"},"description":"Don't look at me\u2026I do what he does \u2014 just slower. #rstats avuncular \u2022 ?Resistance Fighter \u2022 Cook \u2022 Christian \u2022 [Master] Chef des Donn\u00e9es de S\u00e9curit\u00e9 @ @rapid7","sameAs":["http:\/\/rud.is"],"url":"https:\/\/rud.is\/b\/author\/hrbrmstr\/"}]}},"jetpack_featured_media_url":"","jetpack_shortlink":"https:\/\/wp.me\/p23idr-3nW","jetpack_likes_enabled":true,"jetpack-related-posts":[{"id":12940,"url":"https:\/\/rud.is\/b\/2021\/02\/07\/getting-a-handle-on-macos-app-entitlements-with-r\/","url_meta":{"origin":13016,"position":0},"title":"Getting a Handle on macOS App Entitlements with R","author":"hrbrmstr","date":"2021-02-07","format":false,"excerpt":"If you've been following me around the internets for a while you've likely heard me pontificate about the need to be aware of and reduce \u2014 when possible \u2014 your personal \"cyber\" attack surface. One of the ways you can do that is to install as few applications as possible\u2026","rel":"","context":"In &quot;Information Security&quot;","block_context":{"text":"Information Security","link":"https:\/\/rud.is\/b\/category\/information-security\/"},"img":{"alt_text":"macos app entitlements","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2021\/02\/ent-grph-02.png?fit=1138%2C1200&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2021\/02\/ent-grph-02.png?fit=1138%2C1200&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2021\/02\/ent-grph-02.png?fit=1138%2C1200&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2021\/02\/ent-grph-02.png?fit=1138%2C1200&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2021\/02\/ent-grph-02.png?fit=1138%2C1200&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":10991,"url":"https:\/\/rud.is\/b\/2018\/07\/06\/visualizing-macos-app-usage\/","url_meta":{"origin":13016,"position":1},"title":"Visualizing macOS App Usage with a Little Help from osqueryr &#038; mactheknife","author":"hrbrmstr","date":"2018-07-06","format":false,"excerpt":"Both my osqueryr and macthekinfe packages have had a few updates and I wanted to put together a fun example (it being Friday, and all) for what you can do with them. All my packages are now on GitHub and GitLab and I'll be maintaining them on both so I\u2026","rel":"","context":"In &quot;R&quot;","block_context":{"text":"R","link":"https:\/\/rud.is\/b\/category\/r\/"},"img":{"alt_text":"","src":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/07\/app-lod-tree-1.png?fit=1200%2C1197&ssl=1&resize=350%2C200","width":350,"height":200,"srcset":"https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/07\/app-lod-tree-1.png?fit=1200%2C1197&ssl=1&resize=350%2C200 1x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/07\/app-lod-tree-1.png?fit=1200%2C1197&ssl=1&resize=525%2C300 1.5x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/07\/app-lod-tree-1.png?fit=1200%2C1197&ssl=1&resize=700%2C400 2x, https:\/\/i0.wp.com\/rud.is\/b\/wp-content\/uploads\/2018\/07\/app-lod-tree-1.png?fit=1200%2C1197&ssl=1&resize=1050%2C600 3x"},"classes":[]},{"id":12257,"url":"https:\/\/rud.is\/b\/2019\/06\/02\/trawling-through-ios-backups-for-treasure-a-k-a-how-to-fish-for-target-files-in-ios-backups-with-r\/","url_meta":{"origin":13016,"position":2},"title":"Trawling Through iOS Backups For Treasure (a.k.a. How to fish for target files in iOS backups) with R","author":"hrbrmstr","date":"2019-06-02","format":false,"excerpt":"In a recent previous post I brazenly talked over the \"hard parts\" of how I got to the target SQLite file that houses \"mowing history\" for what has become my weekend obsession. So, we'll cover just how to do that (find things in iOS backups) in this post along with\u2026","rel":"","context":"In &quot;iOS&quot;","block_context":{"text":"iOS","link":"https:\/\/rud.is\/b\/category\/ios\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":12537,"url":"https:\/\/rud.is\/b\/2019\/10\/28\/spelunking-macos-screentime-app-usage-with-r\/","url_meta":{"origin":13016,"position":3},"title":"Spelunking macOS &#8216;ScreenTime&#8217; App Usage with R","author":"hrbrmstr","date":"2019-10-28","format":false,"excerpt":"Apple has brought Screen Time to macOS for some time now and that means it has to store this data somewhere. Thankfully, Sarah Edwards has foraged through the macOS filesystem for us and explained where these bits of knowledge are in her post, Knowledge is Power! Using the macOS\/iOS knowledgeC.db\u2026","rel":"","context":"In &quot;macOS&quot;","block_context":{"text":"macOS","link":"https:\/\/rud.is\/b\/category\/macos\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":12645,"url":"https:\/\/rud.is\/b\/2020\/02\/06\/prying-r-script-files-away-from-xcode-et-al-on-macos\/","url_meta":{"origin":13016,"position":4},"title":"Prying &#8220;.R&#8221; Script Files Away from Xcode (et al) on macOS","author":"hrbrmstr","date":"2020-02-06","format":false,"excerpt":"As the maintainer of RSwitch --- and developer of my own (for personal use) macOS, iOS, watchOS, iPadOS and tvOS apps --- I need the full Apple Xcode install around (more R-focused macOS folk can get away with just the command-line tools being installed). As an Apple Developer who insanely\u2026","rel":"","context":"In &quot;macOS&quot;","block_context":{"text":"macOS","link":"https:\/\/rud.is\/b\/category\/macos\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]},{"id":12917,"url":"https:\/\/rud.is\/b\/2021\/01\/26\/making-it-easier-to-experiment-with-compiled-swift-code-in-r\/","url_meta":{"origin":13016,"position":5},"title":"Making It Easier To Experiment With Compiled Swift Code In R","author":"hrbrmstr","date":"2021-01-26","format":false,"excerpt":"The past two posts have (lightly) introduced how to use compiled Swift code in R, but they've involved a bunch of \"scary\" command line machinations and incantations. One feature of {Rcpp} I've always ? is the cppFunction() (\"r-lib\" zealots have a similar cpp11::cpp_function()) which lets one experiment with C[++] code\u2026","rel":"","context":"In &quot;macOS&quot;","block_context":{"text":"macOS","link":"https:\/\/rud.is\/b\/category\/macos\/"},"img":{"alt_text":"","src":"","width":0,"height":0},"classes":[]}],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/13016","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/comments?post=13016"}],"version-history":[{"count":0,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/posts\/13016\/revisions"}],"wp:attachment":[{"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/media?parent=13016"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/categories?post=13016"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/rud.is\/b\/wp-json\/wp\/v2\/tags?post=13016"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}