Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

Caleb531

macrumors 6502
Original poster
Oct 17, 2009
289
0
I have not found an answer yet so I'm hoping someone here can help me. I don't know a great deal about PLIST files, so forgive me if I do not use the proper terminology.

I am trying to write an AppleScript to change the value of the Info.plist file for iWork '09 Pages. I know how I can write to a value, but not how to write to a child value. I am trying to change the value CFBundleTypeRole of item 8 of CFBundleDocumentTypes. This is the script I have so far:

set plist to do shell script "defaults read /Applications/\\iWork\\ \\'09\\/Pages.app/Contents/Info CFBundleDocumentTypes"

I do not know how to get any further than that. Any help would be greatly appreciated.
 
Give up. Forget it. Abandon all hope. It's an enormous PITA to use 'defaults' with any nested objects.

Use plistbuddy instead. Google it.
 
Ya, defaults does not work very well once you are past the first layer, and PlistBuddy is a bit better. If you are looking to change it to a single value than that might be your best option.

Once it gets just a little more complicated I usually switch up to using Python. If you can get away without supporting older versions (so 10.5 and up), then it gets very nice to use. Here is some simple sample code:
Code:
#!/bin/env python

import Foundation

# read in the data
plistNSData = Foundation.NSData.dataWithContentsOfFile_("/Applications/iWork '09/Pages.app/Contents/Info.plist")
plistData, format, error = Foundation.NSPropertyListSerialization.propertyListFromData_mutabilityOption_format_errorDescription_(plistNSData, Foundation.NSPropertyListMutableContainersAndLeaves, None, None)

# search for exactly the data we want, and change it
for thisBundleType in plistData["CFBundleDocumentTypes"]:
	if "CFBundleTypeName" in thisBundleType and thisBundleType["CFBundleTypeName"] == "SLDocumentTypeRichTextBundle":
		thisBundleType["CFBundleTypeRole"] = "Reader"

# write the data back out (to a temp file)
plistNSData, error = Foundation.NSPropertyListSerialization.dataFromPropertyList_format_errorDescription_(plistData, format, None)
plistNSData.writeToFile_atomically_("/tmp/sampleChangedData.plist", True)

Two notes: watch out for this web page swallowing some code or formatting (very important with Python), and you will have to change the particulars to doing what you want. Right now it is saving things back to a temp file rather than the real one.

Oh... and I omitted all error handling code, which production code should have. So if something goes wrong this is likely to dig itself a bit of a ditch.
 
Is plistbuddy installed by default? How about all the way back to 10.4? Can someone post a simple example of this in action?

I am trying to do a similar thing as the OP.
 
It's been a while since I did this, and I no longer have access to the code, but python has a plist editing library.
 
It's been a while since I did this, and I no longer have access to the code, but python has a plist editing library.

plistlib has a lot of problems: It can't work with binary plists, it can work with plists that have dates in them, there are some oddities converting numbers, and a few other issues.

It is far better to use things through the Obj-C bridge. As you can see from my example above, with just a few lines (maybe 2 more than using plistlib), you have Python objects that you can use and work with natively (dates are a little fiddly, but fairly easy to work with).
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.