How To Change Preferences from the Command Line on macOS?

Channel: mac
Abstract: ~]$ defaults read com.apple.TextEdit~]$ defaults delete com.apple.TextEdit CheckGrammarWithSpelling

The user friendly way to change an application preferences (aka settings) in macOS is to use the UI menu as Application Name > Preferences... or by typing the shortcut ⌘+, from the given application.

Though, this user interface based method doesn’t allow you to version control your preferences with git or programmatically set your applications preferences from a shell script. This is where the macOS command line tool defaults comes handy. defaults lets you read, write, and delete user preferences from the command line.

This post covers:

What is the defaults command line?

defaults access the Mac OS X user defaults system, i.e. preferences. All Mac OS X application use the defaults system to record user preferences and other informations that must be maintained when the applications are not running.

It is worth noting that you can often access more options through the defaults command line than when using the user interface. Also, keep in mind that if you change the settings of a running application, the application may not see the change until it get restarted and/or may overwrite the change.

User defaults belong to domains which generally represented a unique domain for each application. Each domain will be represented a dictionary of key/value; for example, 「Default Font」 = 「Arial」. Keys are always strings but the values may be complex data structures comprising arrays, dictionaries, strings, and binary data. Those data structures are stored as XML Property Lists and are known as plist.

How to use the defaults command line?

defaults comes with a few available commands to read, write, and delete user applications preferences from the command line.

readprints the user’s settings to standard outputread-typeprints the plist type for a given keywritewrite a value for the given keyrenamerename a keyimportimport a plist to a given domainexportexport a domain and all the keys as a plistdeletedelete a given key or a domain / all keys for a given domaindomainsprints the name of all domainsfindsearch all domains, keys, and values for a given word

Make sure to take a look at the man defaults for the full details or simply run the command line without any argument as defaults to get the basic help message.

ExamplesFind Out the Domains of Installed Applications

If you simply use defaults domains you may end-up with a long list of comma separated domains that is not necessary easy to read.

[…] com.apple.Spotlight, com.apple.SystemProfiler, com.apple.TelephonyUtilities, com.apple.Terminal, com.apple.TextEdit, com.apple.UIKit, com.apple.UserAccountUpdater, com.apple.WebKit.WebContent, com.apple.accounts […]

You can easily make that list output prettier by using tr with something like defaults domains | tr ',' '\n'.

[…]
com.apple.Terminal
com.apple.TextEdit
[…]

You will still end-up with hundreds of lines and you may have to grep your way through if you are unsure which domains you are looking for.

Find The Domain And Read a Key

Lets say you want to programmatically enable the Check grammar with spelling in TextEdit. To find the domain, we will first use the above command defaults domains and grep for the application name.

[me@me-macOS: ~]$ defaults domains | tr ',' '\n' | grep -i textedit
com.apple.TextEdit

Then we can simply read the existing defaults for TextEdit with defaults read <domain>. You won’t see anything fancy there as the option we are interested in won’t be present yet.

[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
    NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
    "NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}

In order to find out the option name, we do have to go in the TextEdit UI and edit the preference manually. Use ⌘+, then in New Document check the box named Check grammar with spelling. Close the preference pane.

Now, if you run again the defaults command above, your new output should look like as below and include the CheckGrammarWithSpelling key.

[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
    CheckGrammarWithSpelling = 1;
    NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
    NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
    "NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}

So, we now know that the key we want to use in our script is CheckGrammarWithSpelling and the domain is com.apple.TextEdit.

This method works fine for simple options but in some case you may have to resort to using diff on the full export of the defaults read file in order to easily find domain and keys impacted.

Write a new Value to a given Key

In order to write a new value to a key, you need to first know what is the value’s type. This is where the command defaults read-type becomes necessary. The key must exist in the defaults in order to return successfully. From our previous TextEdit example, the CheckGrammarWithSpelling key expect a Boolean value.

[me@me-macOS: ~]$ defaults read-type com.apple.TextEdit CheckGrammarWithSpelling
Type is boolean

Once you know that, you can easily write your new settings using the defaults write command.

[me@me-macOS: ~]$ defaults write com.apple.TextEdit CheckGrammarWithSpelling -bool true
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
    CheckGrammarWithSpelling = 1;
    NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
    NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
    "NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}

Note that, in this case, because of the boolean, using an integer would also work; for example: defaults write com.apple.TextEdit CheckGrammarWithSpelling 1.

Delete a Given Key

In the event you want to reset completely the defaults configuration of an application or remove a change you made, then you may want to delete a key or a domain. Though, I would recommend instead to overwrite the preference key with a new value instead as it is less destructive.

In our previous example, if we want to restore our TextEdit preference to its default we can simply run defaults delete on the given key.

[me@me-macOS: ~]$ defaults delete com.apple.TextEdit CheckGrammarWithSpelling 
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
{
    NSNavLastRootDirectory = "~/Library/Mobile Documents/com~apple~TextEdit/Documents";
    NSNavPanelExpandedSizeForOpenMode = "{799, 448}";
    "NSWindow Frame NSNavPanelAutosaveName" = "320 334 799 390 0 0 1440 877 ";
}

If you completely delete a domain then, the next time you read that domain will fail.

[me@me-macOS: ~]$ defaults delete com.apple.TextEdit
[me@me-macOS: ~]$ defaults read com.apple.TextEdit
2020-05-03 21:38:44.129 defaults[28419:688204] 
Domain /Users/me/Library/Containers/com.apple.TextEdit/Data/Library/Preferences/com.apple.TextEdit does not exist

The preference would shows up again the next time you start the application as it will write a new set of defaults.

Going Further

Some people have been going quite far on how to customize their macOS working environment with a fully scripted customization of their various apps, including the Finder itself. A nice example to check is the config from Mathias Bynens and also a great inventory of various peoples dotFiles curated by Wilson Mar.

Ref From: shell-tips

Related articles