Macではdefaults
というコマンドを使ってコマンドラインからシステムの設定や
アプリ毎の設定を確認したり変えたりすることが出来ます。
ただ、どの様な事が出来るのか、は色々な所で書かれてる物を断片的に集めるしか無く、 何が出来るのか知る術がなかなかよい方法がありません。
defaults
コマンドそのもので現在設定されている物は確認出来るので、
そこからコマンドに戻してあげればある程度使いたい設定項目が
分かるだろう、ということでそのリストを作るコマンドを作ってみました。
parse-plist
ということで作った物が以下にあります。
bin/parse-listを適当なPATHの通ったディレクトリに入れるか、 Homebrewで
$ brew install rcmdnk/rcmdnkpac/parse-plist
でも入れられます。
何が出来るかというと、defaults
コマンドの出力を解析して
defaults write "com.apple.dock" "orientation" -string "bottom"
みたいな実際にコマンドラインから実行できる形のコマンドリストを作ります。
以下、実際何をやってるかについてちょっと説明。
プロパティリスト
Macでは プロパティリスト(property list, plist) と呼ばれるファイルで 色々な設定項目を保存しています。
plist
はいくつかのフォーマットで書くことが出来て、
現在はほとんどがバイナリーファイルかXMLファイルになっています。
/Library/Preferences、/User/$USER/Library/Preferences
等に環境設定ファイル群としてのplist
が見つけられます。
また、
/Applications/Firefox.app/Contents/Info.plist
の様にアプリの中にもplist
が入っています。
ただ、アプリの後付の設定は
/Users/$USER/Library/Preferences/org.mozilla.firefox.plist
みたいに別途用意されていることが殆どです。
(アプリ内の物は後から変更しない。)
これらの設定を一通り見たい場合にはdefaults read
コマンドを使うと
$ defaults read
{
"Apple Global Domain" = {
AppleAntiAliasingThreshold = 4;
AppleAquaColorVariant = 6;
AppleEnableSwipeNavigateWithScrolls = 1;
AppleHighlightColor = "0.500000 0.500000 0.500000";
AppleInterfaceStyle = Dark;
AppleKeyboardUIMode = 1;
AppleLanguages = (
ja,
en
);
AppleLocale = "ja_JP";
....
と言った具合に NEXTSTEP と呼ばれるフォーマットで出力されます。
この時、表示されるのは /Library/Preferences、/User/$USER/Library/Preferencesの下にあるもの全て、 です。(一応多分。)
/Applications/Firefox.app/Contents/Info.plistみたいな内容は表示されません。
また、必要な設定だけ欲しい時には欲しいドメインを指定します。
$ defaults read org.mozilla.firefox.plist
{
NSNavPanelExpandedSizeForOpenMode = "{..., ...}";
NSNavPanelExpandedSizeForSaveMode = "{..., ...}";
NSNavPanelExpandedStateForSaveMode = 1;
NSTreatUnknownArgumentsAsOpen = NO;
PMPrintingExpandedStateForPrint2 = 1;
}
の様に一部だけ表示する事が出来ます。
ドメインはdefaults
コマンドで設定を書くときとかにも最初に与える物で、
/Library/Preferences、/User/$USER/Library/Preferences等の
下にあるplistのファイル名そのものです。
この表示されるJSONみたいなフォーマットは元々plist
にも使われてたものですが、
OS X 10.0からこのフォーマットをplist
で使うことは非推奨になっています。
ただ、人間には読みやすいフォーマットなのでdefaults read
のデフォルト出力形式となっているようです。
最初このフォーマットがJSON的な感じだから簡単に扱いやすいだろう、 と思って適当に解析してみようと思いましたが、 以外とこのフォーマットを解析するのが面倒で途中で辞めました。
defaults
コマンドにはread
の他に、export
というサブコマンドもあって、
これを使うとNEXTSTEP以外のフォーマットで設定を書き出すことが出来ます。
export
を使うときには必ず出力先を指定する必要があって、
$ defaults export org.mozilla.firefox.plist ./test.plist
の様に通常ファイルを指定するとバイナリのplistが書き出されます。
一方、-
を指定すると標準出力にXML形式で表示します。
$ defaults export org.mozilla.firefox.plist -
<?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>
<key>NSNavLastRootDirectory</key>
<string>~/Dropbox/04_Physics/21_DoubleChooz/DCJMeeting</string>
<key>NSNavPanelExpandedSizeForOpenMode</key>
<string>{..., ...}</string>
<key>NSNavPanelExpandedSizeForSaveMode</key>
<string>{..., ...}</string>
<key>NSNavPanelExpandedStateForSaveMode</key>
<true/>
<key>NSTreatUnknownArgumentsAsOpen</key>
<string>NO</string>
<key>PMPrintingExpandedStateForPrint2</key>
<true/>
</dict>
</plist>
plist
を扱いやすいものに変換する方法は色々あるようですが
1、
XML形式に関しては色々と解析するツールもあるので、こちらを使うことにしました。
plistの解析方法
plist
をXMLにすると、XMLの要素としては
string
, real
, integer
, true
, false
, data
, date
, array
, dict
が含まれています。
取り敢えずPythonで色々扱いたいということで、 扱いやすいJSON型に変更したいと思います。
ただし、XMLの要素になってるもののうち、date
, data
はJSONで対応するものが無いため、
JSON形式に変換するときに問題が起こります。
実際、defaults
以外にもいくつかMacでplist
関連のコマンドがあって、
plutil
というコマンドがあるのですが、
このコマンドはJSON型にplist
を変更することができるものの、
data
, data
型が混じってると失敗します。
$ plutil -convert json <INPUT> -o <OUTPU>
plutil
はこんな感じで<INPUT>
を-convert
で指定したフォーマットで<OUTPUT>
に書き出せます(<INPUT>
、<OUTPUT>
それぞれ-
にすることで標準入力、標準出力になります)。
<INPUT>
の形式はplist
のものならなんでもOK。
(バイナリ、XML、JSON等。)
ただ、plist
の中にdate
やdate
があると
$ defaults export com.apple.dock.plist -|plutil -convert json - -o -
<stdin>: invalid object in plist for destination format
こんな感じでJSONにしようとするとこけてしまいます。
そこで、一旦XMLを自前で解析してみることにしました。
xml.dom.minidomを使った解析
XMLをminidomを使って解析します。
最終的にJSON形式とかにしたいのですが、
date
とかはこの時点でどうするか難しいんですが、
ここでは取り敢えず文字列にして、最初にdate:
等と付け加えて保存しておくことにします。
実際にやってみたのがこんなコード。
主にcheck_node
の部分でXMLの各要素が何かを見て
JSONのリストに埋めていっています。
それを最終的にdefaults
コマンドに書き換えていますが、
date
やdate
の部分は変換時にきちんと治せてる保証はありません。
それから結構面倒な事をしてますが、結局のところ、
date
とかの内容をそのまま文字列にして頭にdate:
とか付けてるだけなので、
だったらXMLの状態で要素名を変えてしまってから変更すれば良いのでは、ということで次。
plutilを使う
現状バージョンの方ですが、こちらでは
最初defaults
コマンドでXMLにして書きだした後、
plutil
でJSONに変換しています。
この際、XMLの中のdate
、data
要素はstring
に書き換え、
加えてその中身をdate:
みたいに書き換えています。
これでplutil
に与えてもエラー無く変換できるようになります。
XML出力しないでバイナリをplutil
に与えることも出来ますが、
上の様な変換が必要なので一旦XMLにする過程を踏む必要があります。
また、一部日本語とかの取扱で、
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)
みたいなエラーが出ることがあるので、
print
する前に
import codecs
sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
としてstdout
をcodecs
でラップしてあります
2。
使い方
取り敢えず現状ある設定をするコマンドを知りたければ
$ parse-plist
defaults write "com.adobe.air.ApplicationInstaller" "NSNavLastRootDirectory" -string "~/Applications"
defaults write "com.adobe.air.ApplicationInstaller" "NSNavPanelExpandedSizeForOpenMode" -string "{1680, 1023}"
defaults write "com.apple.ActivityMonitor" "OpenMainWindow" -bool False
defaults write "com.apple.ActivityMonitor" "ShowCategory" -int 100
...
こんな感じでparse-plist
を行えばdefaults read
で見れる様な設定の
defaults
コマンドが見れます。
一方、一部のplist
だけを表示したい場合は
$ parse-plist com.apple.dock.plist
defaults write "com.apple.dock" "orientation" -string "bottom"
defaults write "com.apple.dock" "showMissionControlGestureEnabled" -bool True
defaults write "com.apple.dock" "autohide" -bool True
...
の様にドメインを与えればOK。この場合、拡張子のplist
を省略しても構いません。
また、ファイル等をパスを含めて直接指定することも出来ます。
ただし、設定がdate
やdata
、もしくは配列や辞書を中に持つものはきちんと
コマンドとして成立してない部分があります。
従って、これらのものはデフォルトでは無視して出力しないようにしています。
これらも含めて出力するにはparse-plist --date
のように個々の出力を指定するか、
parse-plist --all
として全て出力するようには一応出来ます。
取り敢えずこんな感じでdefaults
コマンドの一覧が見れるようになるよ、というもの。
もうちょっと色々やってみようというところ
既に上のスクリプトに入ってますが
$ parse-plist --user
とすると、
/User/$USER/Library/Preferences
を一旦対比させてparse-plist
を実行し、さらに戻してからもう一回実行し、
差分を表示させる事が出来ます。
これによって、自分が変更した部分を調べる、ということがしたかったんですが、 実はデフォルトでも /User/$USER/Library/Preferences の中に書かれているものは沢山あって、これらが全て出力されてしまいます。
なので、自分が変更したものだけ、ではなくて、単に /User/$USER/Library/Preferences で設定されてるもの全て、が得られるだけです。
同夜に
$ parse-plist --system
をすれば /Library/Preferences 無しの状態とありの状態で比べる事になりますが、これも単にここにあるものをリストするだけ。
なので本来欲しかったものとは違います。
ユーザー領域の方に関しては、新たなユーザーを作ってそこで出来た マッサラなPreferencesを取ってくることでそれに一時的に置き換えてチェック、 みたいなことはしようと思えば出来て、ちょっと手動でやってみましたが、 まあまあ、欲しいものが得られました。
ただ、/Library以下のものは初期設定を得る方法が無いので、 (再インストールすれば良いわけですが。。。) どうしようもないな、と。
いずれにしろ、簡単に初期状態との比較を取ることが思いつきません。
ユーザーを初期化したら出来るPreferencesがあるので、 どこかには情報があるわけで、どうにかすれば取れるんでしょうが、 良く分かりません。
ということで、取り敢えず現状、単に今あるplist
をdefaults
コマンドに
なんとなく変更できるようになった、と言うだけの状態です。
勿論、この状態だと、初期で使われていない値で自分も使ってないものは見れません。 (むしろそれを知る事が一番やりたいことだったり。。。)
1つ事としては、まず1回コマンドリストを書き出しておいて、
環境設定やその他環境設定が出来るアプリなんかで設定を変えた後、
もう一度リストを書き出し、
そのdiff
を取って変更点を見ることで環境設定などの変更を
defaults
コマンドの形で知ることが出来る、ということくらいです。
取り敢えず今のところあまり使い物にならないですが、 今後のためのメモとして残しておきます。
- Parsing specific JSON-like data (NextSTEP PList) from Ruby - Stack Overflow
- iphone - How to convert NextStep plist to JSON - Stack Overflow
- plistlib – Mac OS X のプロパティリストファイルを扱う - Python Module of the Week
- binplist - Binary property list (plist) parser module written in python. - Google Project Hosting
- plist-to-json
- [osx - How to write in a
structure with defaults write? - Super User](http://superuser.com/questions/438367/how-to-write-in-a-arraydict-structure-with-defaults-write) - wrangling macs: Using plists from Python ↩