NOTE: Again, I was going to give this presentation for MacDMV this month, however, due to unannounced circumstances I wonât be able to present. Here is what I was going to post immediately following the meet-up.
Part 1 of my regex series gave fundamental examples on how to use regex depending on if you want to find words at the begging, middle, or the end of multiple lines of text. This section will try to provide examples that are closer to Mac Admin thus being more useful.
Mac Admin Examples
Letâs take our knowledge gained from the previous article and apply it to a more practical (or at least somewhat a practical) example that an Mac Admin may want to accomplish; read a plist file. YES, defaults read would be much easier. YES /usr/libexec/PlistBuddy would be another reasonable solution⌠but weâre playing with regex so grab a chair and sit down!
Regex the Dock
My first example weâll read the Dock (com.apple.dock.plist). The dock is located on a per user basis, thus it lives in the Userâs Library => Preference folder. Letâs find out information regarding our dock, first letâs print the entire file.
defaults read ~/Library/Preferences/com.apple.dock.plist
Itâs big! Iâm not going to paste that into an article that is already too long.
For fun (and to validate our future results) how many times does âbundle-identifierâ occur (I get 24)?
defaults read ~/Library/Preferences/com.apple.dock.plist | grep -c '"bundle-identifier"'
Find the âbundle-identifierâ
Our goal is to find the text that follows each âbundle-identifierâ so we can see each of the unique reverse URL strings that point to an icon. To do this I followed this logic when creating my regex:
- Use
("bundle-identifier")
- Use
(.+)
to include stuff after âbundle-identifierâ - Use
(";$)
to stop at the end of the line - Insert
?<=
in the beginning of the bundle-identifier section to exclude the words bundle-identifier from the results - Insert
?=
in the beginning of the â;$ section to exclude from the result - Insert
= "
at the end of the bundle-identifier section to remove from search results - Replace
(.+)
to a more specific(\S+)
search string (I wanted something more than âanythingâ.\S
does âMatches anything but white space charactersâ.\D
wonât work because âSubline 3â (com.sublimetext.3) and âTextual 5â (com.codeux.irc.textual5) have numbers in their names.)
What the below video example as I type out each of the above sections to get my final result.
Picture example

Now Find the _CFURLString

Now Find the file-label

Some of you may notice that âbundle-identifierâ has 24 results while â_CFURLStringâ has 27. I have three folders in my Dock thus they donât have a bundle-identifier, just the folder path sting that is returned from â_CFURLStringâ. The file-label result was tricky to figureout, but still simple in design. I had to take into consideration that the label may NOT have quotations surrounding the label as they will only appear when there is a space in the name.
To use an awk example of the same goal, we find the bundle-dentifier and then trim out the extra âstuffâ away from our result with gsub
:
justinrummel@Rummel-MBPr ~/D/G/jr.com-hpstr> defaults read ~/Library/Preferences/com.apple.dock.plist | awk '/"bundle-identifier" / { gsub("\"", "", $NF); gsub(";", "", $NF); print $NF}'
com.apple.launchpad.launcher
com.apple.appstore
com.apple.ActivityMonitor
com.apple.Console
com.codeux.irc.textual5
com.tapbots.TweetbotMac
com.apple.FaceTime
com.apple.iChat
com.apple.Safari
com.google.Chrome
com.mailplaneapp.Mailplane3
com.apple.mail
com.apple.AddressBook
com.apple.iCal
com.apple.Notes
com.apple.reminders
com.apple.Maps
com.apple.iTunes
com.apple.iBooksX
com.apple.systempreferences
com.smileonmymac.PDFpenPro6.MacAppStore
com.sublimetext.3
com.apple.RemoteDesktop
com.jamfsoftware.selfservice
Create an AutoPKG Processor
Making â.jssâ or â.munkiâ recipes is strait forward by a quick copy and paste from one of the multiple examples that have already been built, but they are only useful if a â.pkgâ and/or â.downloadâ parent recipe are available! Fortunately, the Autopkg team have the processor called URLTextSearcher which makes creating the â.downloadâ simple! 1
Example #1
For the first example Iâm going to use Shea Craigâs Vivaldi.download.recipe. There are three processors that are being used:
- URLTextSearcher
- URLDownloader
- EndOfCheckPhase
The âURLDownloaderâ performs the download operation and âEndOfCheckPhaseâ ensure it was a successful download, the item we are going to focus on is âURLTextSearcherâ which tells URLDownloader WHAT to download.
âURLTextSearcherâ has two Arguments that are required: âurlâ (our source URL) and âre_patternâ (regex!)
What Shea is requesting is for Autopkg to visit our URL âhttps://vivaldi.comâ and find the regex pattern of âhttps://vivaldi.com/download/Vivaldi[0-9TP_.]+.dmgâ. The actual regex is being displayed in the brackets (along with just before and after), so letâs focus dissecting in this area.
Vivaldi
Having this in the beginning states the download name MUST start with âVivaldiâ[0-9]
This section states any number from zero to 9 may possibly in use[TP]
This section states the only these letters are being used after Vivaldi[_.]
This section states the only two special characters that may also be used are â_â and â.â[+\.dmg]
This is the end of our download file. The â+â states look for a long pattern, then you will find our â.dmgâ (and donât forget to escape our dot in front of the dmg!)
This regex works great, however, the âTPâ letters in the middle of the name worry me. Vivaldi may strip the TP letters because sometime in the future Vivaldi may not be a âTechnical Previewâ, however, what if they replaced that with âRCâ for release candidate? Everyoneâs pkg, jss, munki recipes would start generating fail messages because the name changed outside of the acceptable regex pattern. What we could do is simply state as long as the download file ends with âDMGâ, then give it to me! I would assume then the file name could contain letters, numbers, and special characters, but not spaces. From âPart 1â we learned that \S
will do that assumption just fine, thus line 31 would be:
<string>https://vivaldi.com/download/[\S]+\.dmg</string>
Example #2
For my second example I applied the same theory when reviewing Vivaldi to create a new recipe for Wiresharkâs Development release installer. If you havenât heard, Wiresharkâs Development Release can be used without installing X11 on your machine as they are moving away from XQuarts to Qt. By using the same AutoPkg processor âURLTextSearcherâ, I could scrap the page to find only the development releases vs. the âStableâ or even the âOld Stableâ options.
I reviewed the HTML source for the download page to see what patterns I could extract that said this file is a development release vs. the other two releases, and I believe a development release is based off of: 2
- The Development version is separated into three number tuple
- The first section is the number 1
- The second section is two digits, but the first digit is greater than 1
- The third section is consists of 1 or 2 digits
- Ends with âIntel 64.dmgâ
This gave me the regex of: <string>Wireshark 1\.[2-9][1-9]\.\d{1,2} Intel 64\.dmg</string>
and is now available on my official autopkg repo located at: https://github.com/autopkg/justinrummel-recipes/tree/master/WiresharkDev.
Footnotes
-
This assume the application that you want to create a â.downloadâ recipe is not being provided by the Sparkel framework, as that is a separate processor. ↩
-
I know at some point I may have to return to https://wiki.wireshark.org/Development/ReleaseNumbers to get a better definition of the development release number, but for now this assumption works. ↩
Comments are closed. If you have a question concerning the content of this page, please feel free to contact me.
Comments
Justin
Be sure to check out Alliaterâs overview about creating new download AutoPkg recipes.\r\n\r\n https://www.afp548.com/2015/04/06/autopkg-download-recipe-decision-making-process/ \r\n