Last week, fellow MacAdmin Kyle Crawford has discovered that on macOS High Sierra the defaults
will delete a property list file with invalid plist/XML syntax, even when you just attempt to read data. Erik Holtham has a more detailed OpenRadar bug.
Patrik Wardle has found the relevant code, which deletes the file when it doesn’t validate.
This is bad. Thanks to all involved for finding, documenting and sharing this.
This is new behavior in High Sierra. I am not yet sure which version of High Sierra this new behavior was introduced. The behavior makes sense in the context of an application attempting to read a settings file, but the defaults
tool deleting arbitrary files is, of course, dangerous.
Update: This behavior has been fixed in 10.13.4. However, it is still good practice to avoid
defaults
for anything other than actual preferences files.
What to do?
As usual, don’t panic. This will only affect Macs running High Sierra and corrupt or broken files. However, if you have a script that accidently points the defaults
command at a different file, it will delete that. So you have to use it with care.
It is probably a good practice to verify a file before you attempt to modify it with the defaults
command in a script with the plutil
command:
if ! plutil -lint path/to/file.plist; then
echo "broken plist"
exit 1
else
defaults path/to/file …
fi
Alternatives to defaults
Alternatively, you can and should use plutil
or PlistBuddy
to read and modify property list files.
Learn more about
plutil
,PlistBuddy
and other tools to read and write property lists in my book: “Property Lists, Preferences and Profiles for Apple Administrators”
plutil
is unfortunately not really useful to read a single value from a property list file. The extract
verb will show any value as its own plist. The plutil
command is useful to edit existing plist files. (Read details on the plutil
command.)
PlistBuddy
, however is very useful for both reading an writing values to a property list file:
$ /usr/libexec/PlistBuddy berry.plist -c "print size"
$ /usr/libexec/PlistBuddy berry.plist -c "set size enormous"
PlistBuddy
has the additional advantage of allowing to add or edit values nested deep in dict
or array
structures.
You can get more information on PlistBuddy
in its man page or my book.
The interactive mode of PlistBuddy
is also very useful.
So the defaults
command is dead?
No.
Apple has been warning us to not use defaults
for generic property list file editing and parsing for quite a while in the defaults
command’s 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.
As this warning states, the defaults
tool reads and writes data to plist files through macOS’s preferences system. This has the advantage that the tool gets (and changes) the current value whether it is cached in memory or not. When an application is listening for notifications that a preference has changed (not many do) then it will be notified.
Files for preference domains are usually stored in /Library/Preferences/
, ~/Library/Preferences
or their ByHost
subfolders. Sandboxed applications will have their preference plist files in their container.
There, however, many other files that are property list files which are not part of the user defaults system: launchd
files, configuration profiles and AutoPkg` recipes to name just a few.
Mac Admins commonly use the defaults
tool, despite Apple’s warning, to create, read and edit generic plist files. As mentioned above, plutil
, PlistBuddy
or direct manipulation through Obj-C, Python or Swift, are better choices for generic plist files.
You can learn about all these options in my book: “Property Lists, Preferences and Profiles for Apple Administrators”