Many Mac tips—on
hints.macworld.com and elsewhere around the Web—require you to use the defaults
command in the Terminal. That command lets you set secret preferences that are otherwise inaccessible. For example, defaults
can help you
get rid of the Ping drop-down in iTunes,
disable OS X’s warnings about opening download files,
show all files in the Finder,
make the Help Viewer behave like a normal window,
set half-star ratings in iTunes,
shrink the Dock dramatically,
dim Dock icons for hidden applications,
tweak the CrashReporter, among many, many other system tweaks.
Trouble is, if you use defaults
to update your system, it can be hard to keep track of all the changes you’ve made. It’d be handy to know what you’ve done for the sake of troubleshooting and moving to a new Mac. Which is why it’s so cool that Hints reader
dgerrity found a way to keep just such a record.
Not surprisingly, his hint involves a bit of Terminal work. What it does is create a new script called “defaults”, then set things up so that whenever you enter a defaults
command in the Terminal, that script runs instead. The script will look at the defaults write
command you’re entered, log that change (along with the original value) to a file, and then pass the command off to the real defaults
command to make the actual change.
First, create our new, customized version of defaults
. Open your favorite text editor, then paste the following into it:
#!/bin/bash# Defaults - a script to record important changes to the systemlf=${HOME}/Library/Logs/com.defaults.logfunction log() { echo "$(date "+%Y-%m-%d %H:%M:%S") bash $@" >> ${lf}; }if [[ ! ${1} ]]; then echo "This is the script version of defaults. Run /usr/bin/defaults to see help" exit 1fiif [[ (${1} == write) || (${1} == delete) ]]; then op=${1}; dom=${2}; key=${3}; shift; shift; shift; args="${@}" [[ (${op} == write) && ("${args}" == "") ]] && args='""' log "${USER} executed defaults ${op} ${dom} ${key} ${args}" logger "${USER} executed defaults ${op} ${dom} ${key} ${args}" log "existing value: "$(/usr/bin/defaults read ${dom} ${key})"" logger "existing value: "$(/usr/bin/defaults read ${dom} ${key})"" /usr/bin/defaults ${op} ${dom} ${key} ${args} log "new value: "$(/usr/bin/defaults read ${dom} ${key})"" logger "new value: "$(/usr/bin/defaults read ${dom} ${key})""else /usr/bin/defaults $@fi
Save that script as a file named defaults
with no extension to your Desktop.
Now you need to put that defaults
file where it’ll do you some good. First, at the Terminal command line type cd /usr/local/bin
, and press Return. Next, to copy the file, type sudo cp ~/Desktop/defaults .
and press Return again. Terminal will prompt you for your password (the one for your administrator account); type that and press Return once more.
If you’re lucky, you’ve just successfully put your new defaults
script in the right place. Chances are, however, that it’s not working yet. There’s an easy test: Type defaults
in your Terminal window and press Return. If you see the message This is the script version of defaults
, you’re running your customized version. If you see something else—like a massive block of text explaining all the functions of the defaults
command—your work is not yet complete.
You need to tell Terminal to prioritize the new defaults
command we just created in /usr/local/bin
over the original (which lives in /usr/bin/
). To do that, we need to edit the file that dictates such priorities. The file in question is /etc/paths
. I edited mine using vim. If you know how to do that, go right ahead. If not, here’s an alternative:
In Terminal, type cp /etc/paths ~/Desktop/paths
and press Return. That copies the paths file from /etc to your Desktop. Find it there and open it in your favorite plain text editor. Find the line /usr/local/bin
and move it above the line /usr/bin
. (If your paths file doesn’t have a /usr/local/bin
line, just insert one above /usr/bin
.) The file will likely have other paths, too—leave those alone. After saving your changes, type sudo mv ~/Desktop/paths /etc/paths
into Terminal and press Return. If you’re prompted to enter your password again, do so, and press Return again.
Now, close your existing Terminal window and open a new one (to ensure that Terminal notices your updated paths
file). Type defaults
once more. If you see the “This is the script version…” message, then you’re cooking with gas. If you still don’t see it, then something’s gone wrong, and you can feel free to curse my name.
Assuming you do get that “This is the script version…” reply, every time you issue a defaults write
command from nowon, your new script will intercept it and log it before implementing it. To test that out, try out this one:
defaults write com.apple.dock showhidden -bool true; killall Dock
(You’ve just told the Dock to render application icons transparent if the apps in question are hidden; killall
restarts the Dock to make the command take effect. Don’t worry if you’ve already enabled this preference; this is just a test. And if you want to reverse this effect, repeat the command above, but replace true
with false
.)
Now check your new log file. Go back into your favorite text editor, choose File -> Open, and then type ~
to summon the Go to the Folder text-entry box. Follow the tilde there with /Library/Logs/com.defaults.log
and press Return. The file should now be highlighted in the Open window. When you open it, it should look something like this:
2011-07-19 10:58:42 bash username executed defaults write com.apple.dock showhidden -bool true2011-07-19 10:58:42 bash existing value: "0"2011-07-19 10:58:43 bash new value: "1"
Now you can see exactly who changed what and when. Should you ever want to stop logging your defaults
changes, just delete your custom /usr/local/bin/defaults
file, and you’ll be back to the command’s original behavior.