研究室や就職先などでのコンピュータのセットアップのために、3月頃からdotfilesを構築している。

その流れでdefaultsコマンドを知ったので、その記録と使い方、調べ方を残しておく。。

defaultsコマンドとは

macOSにおける環境設定や各アプリケーションの設定は.plist拡張子のプロパティリストと言われるファイルに記録される。 このプロパティリストを読み書きするためにmacOSに標準で搭載されているのがdefaultsコマンドである。 (詳細は$ man defaultsしてください。)

これを利用して、OS全体の環境設定やアプリケーションの設定を自動化するスクリプトをつくっている。(実際に作ったスクリプト - yammerjp/dotfiles - GitHub)

今回はこのスクリプトを構築するための話。

参考: Macの「ターミナル」でプロパティリストを編集する - ターミナルユーザガイド - Apple

他人の設定を拝借する

ネット上に他の人がどのコマンドを叩くとどの設定が変更できるかを調べてすでにまとめてくれたものがある。これを拝借するのが第一の手。

公式でどこかに情報がまとまっていればよいのだが、「公式な」設定変更のやり方はGUIから変えることだからか、そんな丁寧なマニュアルはなさそう。

注釈: defaultsコマンドを実行すると、設定変更が即座に反映されるわけではない。以下のように再起動するなどして設定を読み込ませると良い。

# Dockの設定変更を反映
$ killall Dock
# finderの設定変更を反映
$ killall Finder
# メニューバー(画面上部)の設定変更を反映
$ killall SystemUIServer
# その他駄目なら再起動。
$ sudo reboot

設定するコマンドを探す

ネットを探していても自分の思うような設定がみつからないことがある。そのときは以下の手順で調べると見つかるかもしれない。

defaultsコマンドの使い方

前提として、manual($ man defaults)の通り、defaultsコマンドは次のように使う。 以下は簡略に示す。実際に実行する際はmanualを参照。

# すべて読む
$ defaults read

# 読む
$ defaults read DOMAIN KEY
$ defaults read -g KEY
# 書き込む
$ defaults write DOMAIN KEY VALUE
$ defaults write -g KEY VALUE

プロパティリストはkeyとvalueの対が原則で、jsonのようにvalueの中に入れ子でkeyとvalueのまとまりなどが入る。

valueにはstringやdata, int, float, bool, array, dictなどの形式がある。

$defaults writeする際にオプションで-string-array, -array-addとすると希望のデータ型で値を書き込める。

探し方

設定変更前後のプロパティリストの差分から、それっぽい設定項目を見つける。 その後実際に$ defaults writeでプロパティリストを書き換えて、設定が反映されるかを確認する。

このとき、設定変更のためのGUIウィンドウは予め開いておいて、beforeとafterの記録をすると良い。 プロパティリストには我々が手動で設定した環境設定の他にも多用途に利用されているらしく、時間をあけるとあっという間にdiffが汚くなる。

$ defaults read > before

# GUI上で設定を変更する

$ defaults read > after
$ diff before after
# colordiff(brew install colordiff)などを使うと捗る

実際に探す一例

一例として、メニューバーに音量アイコンを表示する設定を探す。

プロパティリストを読む

GUIで設定する前後のプロパティリストを比較する。

プロパティリストを読み込むスクリーンショット

$ defaults read > before
# GUIで設定変更
$ defaults read > after
$ diff before after
6504a6505
>         "NSStatusItem Visible com.apple.menuextra.volume" = 1;
6511c6512,6513
<             "/System/Library/CoreServices/Menu Extras/Bluetooth.menu"
---
>             "/System/Library/CoreServices/Menu Extras/Bluetooth.menu",
>             "/System/Library/CoreServices/Menu Extras/Volume.menu"

差分を見ると、6500行目あたりに設定項目がありそう。

実際にafterの6500行目以降の数行を見てみる。

     "com.apple.systemuiserver" =     {
         "NSStatusItem Visible com.apple.menuextra.airport" = 1;
         "NSStatusItem Visible com.apple.menuextra.battery" = 1;
         "NSStatusItem Visible com.apple.menuextra.bluetooth" = 1;
         "NSStatusItem Visible com.apple.menuextra.clock" = 1;
         "NSStatusItem Visible com.apple.menuextra.volume" = 1;
         "__NSEnableTSMDocumentWindowLevel" = 1;
         "last-analytics-stamp" = "608273612.570469";
         menuExtras =         (
             "/System/Library/CoreServices/Menu Extras/Clock.menu",
             "/System/Library/CoreServices/Menu Extras/Battery.menu",
             "/System/Library/CoreServices/Menu Extras/AirPort.menu",
             "/System/Library/CoreServices/Menu Extras/Bluetooth.menu",
             "/System/Library/CoreServices/Menu Extras/Volume.menu"
         );
     };

以上より、設定は次の内容を書き込めば良さそう。

  • ドメイン com.apple.systemuiserver 、キー NSStatusItem Visible com.apple.menuextra.volume に、値 1 を設定する。
  • ドメイン com.apple.systemuiserver 、キー menuExtra の値の配列に、 /System/Library/CoreServices/Menu Extras/Volume.menu を追加。

シェルスクリプトにまとめると次の通り。

#!/bin/bash -e

# 音量アイコンをMenuBarに表示
defaults write com.apple.systemuiserver \
  "NSStatusItem Visible com.apple.menuextra.volume" 1

defaults write com.apple.systemuiserver \
  menuExtras -array-add "/System/Library/CoreServices/Menu Extras/Volume.menu"

# メニューバーを再起動
killall SystemUIServer

プロパティリストに書き込んで試す

実際に試してみると、反映されていることがわかる。

プロパティリストに書き込むスクリーンショット

なぜdefaultsコマンドを使うのか

メリット

  • 設定を自動化できる

PCで新しく環境構築する際に、シェルスクリプトにまとまっているので一括で設定できる

  • 自分が行っていた設定を記録できる。

自分がGUI上でどんな設定を行っているか、いたかをコードで示すことができる。 アプリケーションがプロパティリストとしてデータを持っているならば、サードパーティアプリケーションでも同様に設定を記録できる。

たとえば、私はShiftItというアプリケーションを使っている。 このアプリケーションで使うキーバインドはGUI上から設定するのだが、自分がどんな設定をしているのかをコードとして記録できるのは、再設定だけでなく今後のなんらかのキーバインド設定の参考にもなる。

参考: 私の現在のShiftItのキーバインド設定

デメリット

  • 設定変更のたびに逐一調べてシェルスクリプトを更新しなければならない

これはたしかに面倒だけどね。 プロパティリストをむやみに書き換えると、パソコンが上手く動かなくなる可能性もある。。

  • OSのアップデートによって設定が適用できなくなるかもしれない

GUIもアップデートで項目がなくなったりどこにいったかわからなくなったりするよね

まとめ

以下を使って頑張ってシェルスクリプトを書こう。

$ defaults read > before
# GUIで設定変更
$ defaults read > after
$ diff before after

$ man defaults

将来の自分へ

diffを読み取ってdefaultsコマンドのシェルスクリプト形式にするのは自動化できるのでは? と思ったが、先駆者がいたようだ