如何在 OS X 上解析"默认读取"的输出?



如何解析 OS Xdefaults read终端命令的输出?

它似乎输出"旧的"NeXTSTEP plist格式;看起来像这样的东西:

{
"Apple Global Domain" =     {
AppleAntiAliasingThreshold = 4;
AppleCollationOrder = root;

我尝试将输出写入文件并使用plutil进行转换,但它阻塞了:

> defaults read > defaults.txt
> plutil -convert xml1 defaults.txt
2014-02-02 21:29:14.856 plutil[56896:707] CFPropertyListCreateFromXMLData(): Old-style
plist parser: missing semicolon in dictionary on line 10835. Parsing will be abandoned.
Break on _CFPropertyListMissingSemicolon to debug.
defaults.txt: Property List error: Unexpected character { at line 1 / JSON error: No
value for key in object around character 28.

你问为什么?

我想将默认值存储在 Git 中,这样我就可以在应用更改后保留记录作为更改设置和差异,但似乎defaults read中的序列化不是"行顺序稳定的":字典不会以一致的顺序转储它们的键,造成大量的噪音。 如果我能解析defaults read, 然后,我可以通过顺序一致的序列化程序将数据传送出去。

plutil 可以转换为 XML 或 JSON

#!/bin/bash
f='~/Library/Preferences/com.apple.LaunchServices/com.apple.launchservices.secure'
x="$(plutil -convert xml1 -o - "$f")"
j="$(plutil -convert json -o - "$f")"

-o -的意思是:将结果打印到 stdout
$f是 plist 格式的输入文件

你是个幸运的人,就在几天前,有人在 PyPi 上发布了 NeXTSTEP plist 格式的解析器—— NSPlist。

所有这些评论都试图有所帮助,但似乎来自那些实际上没有尝试在最近的(至少在2014年之后)macOS上处理defaults read输出的人。

输出不是有效的 JSON 或旧式的、几乎是 JSON 的 NS。它很近。它不能被任何建议的答案解析。

这令人沮丧,在macOS开发世界中一点也不罕见。

下面是一个直接读取默认值的脚本(使用 Swift),而不是解析默认命令的输出:

#!/usr/bin/swift
// Usage:
// dread com.apple.dt.Xcode IDEApplicationwideBuildSettings   
// dread com.apple.dt.Xcode IDEApplicationwideBuildSettings.SYMROOT
// Example:
//         $ dread com.apple.Terminal "Default Window Settings"
// returns $ Basic
import Foundation
var args = CommandLine.arguments
args.removeFirst()
if let suite = args.first, let defaults = UserDefaults(suiteName: suite) {
args.removeFirst()
if let keyPath = args.first, let value = defaults.value(forKeyPath: keyPath) {
print(value)
} else {
print(defaults.dictionaryRepresentation())
}
}

如果将其另存为名为dreadchmod +x dread的文件,则可以读取应用程序的默认值并按如下所示打印出来:

dread com.apple.dt.Xcode IDEApplicationwideBuildSettings

由于这是一个字典,您可以使用以下命令从该字典中读取其中一个键:

dread com.apple.dt.Xcode IDEApplicationwideBuildSettings.SYMROOT

等等。

请原谅我回答您问题的紧密变体。

您会看到,defaults命令行工具默认发出内容层次结构的字符串表示形式,称为[NSObject description],这是一种不正式的格式,没有完整的文档记录,并且不能依赖。如果您在任何日志行中发出 NSObject 后代,则可以看到此格式:

NSLog(@"This is the string representation of a dictionary: %@", myDictionary); 

或在 Xcode 调试器 (LLDB) 中:

po myDictionary

当然 - 当您使用壳牌中的"defaults read"命令时。此格式不用于解析,并且可能会丢失信息,并且不被视为打印对象的任何正确"序列化"。

但是 - 正因为如此,defaults命令提供了export子命令,作为read的替代方案。

令人沮丧的是,这个子命令没有记录在man defaults中,只是偶然地我在defaults helpdefaults -h中找到了它。以下是相关摘录:

export <domain> <path to plist>      saves domain as a binary plist to path
export <domain> -                    writes domain as an xml plist to stdout

这些输出,无论是在磁盘文件上还是以xml打印到stdout,都可以使用普通的Cocoa机器(Foundation从文件或数据收集初始值设定项,NSPropertyListSerialization协议等)安全轻松地解析。例如,如果将第二个变体的 stdout 收集到NSData对象中,则解析它将如下所示:

NSData *outputOfDefaultsCommand;
NSError *error;
NSPropertyListFormat format;
NSDictionary *dict = [NSPropertyListSerialization propertyListWithData: outputOfDefaultsCommand options:NSPropertyListImmutable format:&format error:&error];
if ( !dict || error)
NSLog(@"Failed to read NSDictionary from .plist data output of 'defaults' command. Error:%@", error);
else 
NSLog(@"Parsed 'defaults' output: %@", dict);

你试过defaults export吗? 这将输出一个二进制文件,然后可以使用 plutil 将其转换为 .plist

最新更新