Thursday, January 04, 2007

I assume everyone knows about the defaults(1) command, and that it can be used from the command line to manipulate application's preferences. But what some folks may not know is that it can also be used to muck with almost any plist file. This can be very useful when tearing through plists from the command line or in a shell script.

For example, I can display TextEdit's CFBundleIdentifier with the following command.

Not only can you read the plists, but you can also write to them using the normal defaults write /path/to/file key value technique.

However, I do have one question myself about this. In the TextEdit examples above, is there a way for me to specify that I want to read just the value of, say, the NSSendTypes key, which is in a dictionary, that is in an array, which is itself the value of the NSServices key? I'd love to be able to do this, but I'm not sure of the syntax (or if it's even possible).

Oh, and also take note of this warning from the man page.

WARNING: The defaults command will be changed in an upcoming major release to only operate on preferences domains. General plist manipulation utilities will be folded into a different command-line program.

Curious. That warning doesn't appear in Tiger's version of the man page (which lists a Nov 3, 2003 mod date). I use this technique all the time for scripting Info.plist changes in an automated build process and it would be good to have a dedicated tool to do this.

Though, of course, remembering to make note of the change when Leopard (or, perhaps Leopard++) ships will take some remembering. Hopefully, there will be some overlap with the new tool.

While not entirely sure, I believe it is very difficult (if not impossible) to modify nested values in XML plist files. There is a little known Apple tool called PlistBuddy that can accomplish that much more easily. It is inluded in a number of Apple Installer packages. For example one is located on my computer at:

:-) That is the solution I'm currently using for the problem at hand. However, it's not a general solution because it relies on the fact that defaults happened to display the values for NSSendTypes on one line. So, yes, that works in this case.

However, it doesn't work if the number of items in the array (or whatever) are split onto multiple lines. For example, the following won't work as desired.

I've found that you can indeed write nested values. For instance, you can add an item to the dock using this structure (remove spaces after < . I had to add a space since the server was thinking they were HTML tags):

The problem for me (my programming skills are rudimentary) is that this entry gets added at the end of the plist (and in this case, the dock). I've not found an easy way to change an existing nested value.

I imagine this would be possible by reading out the entire plist (e.g. defaults read com.apple.dock), making your changes, and then writing it all back with a syntax like the above.

Easiest way to edit the plist files is using plistBuddy. But i didn't find this on Leopard.PlistBuddy will be available at /Library/Receipts\/AdditionalEssentials.pkg\/Contents/Resources/PlistBuddy on Tiger.

Defaults can write and delete a key in a plist file and most importantly defaults can't be used to edit values in a plist file.( I am not sure about this ). It can either delete a key or add a key But PlistBuddy can b e used to edit the plist file.