Editing Property Lists with plutil

I stumbled over these option this morning. I do not know when they were introduced, but I can see the options in 10.11 and 10.12. You can see them yourself with plutil -help. (The options are not listed in the man page.)

Note: Managing and editing Property List files and preferences is covered in much more detail and depth in my book “Property Lists, Preferences and Profiles for Apple Administrators

Quick recap: plutil manipulates property list files. Its main use up to now was to convert between property list formats (mainly from binary plists to something readable)

$ plutil -convert xml1 /path/to/propertylist.plist

and to check wether the syntax is valid

$plutil -lint /path/to/propertylist.plist

On Sierra, when you run plutil -help you see some new options. These allow you to directly manipulate keys and values in a property list. This may be useful to replace PListBuddy and defaults to manipulate property lists.

When testing this I noticed one downside of plutil immediately: it cannot be used to create a new property list file. Copy this to create an empty plist file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict/>
</plist>

Inserting a new key/value pair

$ plutil -insert somekey -string somevalue test.plist
$ plutil -insert flag -bool YES test.plist
$ plutil -insert bestNumber -integer 1 test.plist
$ plutil -insert pi -float 3.141592 test.plist

This is pretty straightforward.

Inspecting a property list

You can use the -p option to check our progress:

$ plutil -p test.plist
{
  "newkey" => "newvalue"
  "pi" => 3.141592
  "bestNumber" => 1
  "flag" => 1
}

This uses a non-standard output format, and the help text warns to use this parse plists. But it will do to look at the content.

Note: you can use plutil -p to read the content of binary plists without converting!

Modifying values

You can modify values with the -replace option.

$ plutil -replace flag -bool NO test.plist

Note that you can create new entries with -replace:

$ plutil -replace otherkey -string othervalue test.plist

But you cannot overwrite an existing value with -insert.

Deleting values

Very straightforward:

$ plutil -remove otherkey test.plist

Arrays

You can insert an empty:

$ plutil -insert list -xml '<array/>' test.plist

or

$ plutil -insert list -json '[]' test.plist

and add items to the array

$ plutil -insert list.0 -string 'list item 1' test.plist
$ plutil -insert list.1 -string 'list item 2' test.plist
$ plutil -insert list.2 -string 'list item 3' test.plist

or do it all at once

$ plutil -replace list -json '[ "yes", "no", "maybe" ]' test.plist

Dictionaries

$ plutil -insert dictionary -xml '<dict/>' test.plist
$ plutil -replace dictionary -json '{}' test.plist
$ plutil -insert dictionary.key1 -string value1 test.plist
$ plutil -replace dictionary -json '{ "otherkey" : "othervalue" }' test.plist

Getting Values

It looks like -extract is meant to get values from a property list, but there is caveat. -extract will not merely get the value of a key in the property list but will write it to a new file! And by default if you do not provide an new output file path with the -o option it will overwrite the current file with the extracted data.

The proper, non-destructive syntax to use -extract is:

$ plutil -extract list xml1 -o - test.plist 
$ plutil -extract list json -o - test.plist 

This will print a full property list file to stdout. The -o - option tells plutil to print to stdout. You can give a filename instead of the -.

Since the output is encumbered with the json or xml syntax, it will be hard to use this to get to property list values in shell scripts. However, it still may be useful to, well, extract property list data from a complex plist file.

Conclusion

Keep in mind that there now is an alternative to defaults and PlistBuddy. Not having to convert a plist before changing data might be helpful, as well as the possibility to manipulate arrays and dictionaries with key paths. (You still should always use defaults when working with preference plist files, since defaults will go through the preferences system and possibility notify a process to update data.)

If you are using python or a similar high level scripting language it will still be more effective to use the libraries for property lists.

2 thoughts on “Editing Property Lists with plutil”

  1. Did you come across anyway of working with deeply nested keys and values with plutil?
    For example getting/setting the status in CLOUDDESKTOP:
    defaults read MobileMeAccounts
    {
    Accounts = (
    {
    AccountAlternateDSID = “Blah”;
    AccountDSID = 11111111;
    AccountDescription = iCloud;
    AccountID = “name@domain.com”;
    AccountUUID = “Blah”;
    DisplayName = “First Last”;
    LoggedIn = 1;
    Services = (
    {
    Name = CLOUDDESKTOP;
    ServiceID = “com.apple.Dataclass.CloudDesktop”;
    status = active;
    },
    {
    Name = FAMILY;
    ServiceID = “com.apple.Dataclass.Family”;
    showManageFamily = 1;
    },

    1. plutil -extract Accounts.0.Services.0.status xml1 -o - ~/Library/Preferences/MobileMeAccounts.plist

      or

      /usr/libexec/PlistBuddy -c "Print :Accounts:0:Services:0:status" ~/Library/Preferences/MobileMeAccounts.plist

      I think PlistBuddy is better in this case, since the output of plutil is a full xml plist in itself and harder to parse.

      However, should the order of the items in either the Accounts array or the Services array change you will be messed up. Arrays should preserve order in property lists, but it might be that the process which writes these arrays may not care. You should at the very least verify that :Accounts:0:Services:0:Name is CLOUDDESKTOP before relying on the output of :Accounts:0:Services:0:status

      For reliable results you should use a python script and CFPreferences. Or a Swift tool.

Leave a Reply

Your email address will not be published. Required fields are marked *