发布时间:2026年06月09日 | 分类:黑苹果 | 关键词:PlistBuddy、plist配置、属性列表、自动化脚本

前言:plist——macOS生态的"统一配置语言"

如果你曾经手动编辑过OpenCore的config.plist,或者在终端中修改过某个应用的偏好设置,你就已经与Property List(plist)打过交道了。plist是macOS和iOS生态系统中最核心的结构化数据存储格式,从系统内核参数到应用偏好设置,从启动配置到自动化工作流,几乎一切配置都以plist文件的形式存在。

对于黑苹果用户来说,plist的重要性怎么强调都不为过。你的OpenCore config.plist本质上就是一个庞大的plist文件;你安装的每一个LaunchAgent也是一个plist;甚至系统上的SIP状态、NVRAM启动参数也都以plist格式存储。然而,绝大多数用户对plist的认知停留在"在Xcode或ProperTree中打开编辑"的层面,对于更强大的命令行工具——PlistBuddy——知之甚少。

PlistBuddy(位于 /usr/libexec/PlistBuddy)是Apple内置的plist读写工具,可以让你在脚本中自动化地读取、修改、添加和删除plist中的任意节点,无需GUI编辑器,也无需编写复杂的Python/ObjC代码。掌握PlistBuddy,意味着你可以编写Bash脚本来自动化修改OpenCore配置、批量调整应用偏好、解析系统信息等,将黑苹果的管理效率提升到一个全新的水平。

Property List格式深度解析

两种序列化格式

格式扩展名可读性适用场景
XML plist.plist人类可读(冗长)配置文件、手动编辑
Binary plist.plist不可读系统文件、性能优先
JSON.json人类可读现代应用偏好

核心数据类型

类型XML标签示例
字符串<string><string>Hello</string>
整数<integer><integer>42</integer>
实数<real><real>3.14</real>
布尔<true/> <false/><true/>
日期<date><date>2026-06-09T10:00:00Z</date>
数据<data><data>SGVsbG8=</data>
数组<array>有序列表
字典<dict>键值对集合

格式转换工具

# XML转Binary(减小文件体积)
plutil -convert binary1 config.plist

# Binary转XML(便于编辑)
plutil -convert xml1 config.plist

# 验证plist语法
plutil -lint config.plist

# JSON与plist互转
plutil -convert json -o output.json config.plist
plutil -convert xml1 -o output.plist input.json

PlistBuddy命令行完全手册

基本读取操作

# 打印整个plist
/usr/libexec/PlistBuddy -c "Print" config.plist

# 读取特定键值
/usr/libexec/PlistBuddy -c "Print :PlatformInfo:SMBIOS" config.plist

# 读取数组元素
/usr/libexec/PlistBuddy -c "Print :Kernel:Add:0" config.plist

# 读取字典中的嵌套值
/usr/libexec/PlistBuddy -c "Print :PlatformInfo:Generic:SystemProductName" config.plist

# 以字典格式输出键值对
/usr/libexec/PlistBuddy -c "Print :PlatformInfo:Generic" config.plist

修改操作

# 修改字符串值
/usr/libexec/PlistBuddy -c "Set :PlatformInfo:Generic:SystemProductName iMac20,1" config.plist

# 修改整数
/usr/libexec/PlistBuddy -c "Set :Misc:Boot:Timeout 5" config.plist

# 修改布尔值
/usr/libexec/PlistBuddy -c "Set :Misc:Boot:ShowPicker true" config.plist

# 修改数组中的元素
/usr/libexec/PlistBuddy -c "Set :Kernel:Add:0:Enabled true" config.plist

添加操作

# 添加字符串
/usr/libexec/PlistBuddy -c "Add :NewKey string Value" config.plist

# 添加整数
/usr/libexec/PlistBuddy -c "Add :NewNumber integer 100" config.plist

# 添加布尔
/usr/libexec/PlistBuddy -c "Add :NewFlag bool true" config.plist

# 添加空字典
/usr/libexec/PlistBuddy -c "Add :NewDict dict" config.plist

# 在字典中添加子项
/usr/libexec/PlistBuddy -c "Add :NewDict:SubKey string Hello" config.plist

# 添加空数组
/usr/libexec/PlistBuddy -c "Add :NewArray array" config.plist

# 在数组末尾添加元素
/usr/libexec/PlistBuddy -c "Add :NewArray:0 string FirstItem" config.plist

删除操作

# 删除键
/usr/libexec/PlistBuddy -c "Delete :ObsoleteKey" config.plist

# 删除数组中的元素
/usr/libexec/PlistBuddy -c "Delete :Kernel:Add:5" config.plist

# 删除字典中的键
/usr/libexec/PlistBuddy -c "Delete :PlatformInfo:Generic:ROM" config.plist

高级操作

# 复制值(从一处复制到另一处)
/usr/libexec/PlistBuddy -c "Copy :Source:Key :Dest:Key" config.plist

# 合并两个plist文件
/usr/libexec/PlistBuddy -c "Merge source.plist" config.plist

# 合并特定路径
/usr/libexec/PlistBuddy -c "Merge source.plist :TargetPath" config.plist

# 导入外部数据
/usr/libexec/PlistBuddy -c "Import :NewKey:DataFile data.bin" config.plist

黑苹果实战脚本案例

案例1:OpenCore config.plist批量修改脚本

以下脚本演示了如何用PlistBuddy自动化修改OpenCore配置中最常改动的参数:

#!/bin/bash
# oc_tune.sh - OpenCore配置批量调优脚本
CONFIG="EFI/OC/config.plist"
PB="/usr/libexec/PlistBuddy"

# 开启启动选择界面
$PB -c "Set :Misc:Boot:ShowPicker true" "$CONFIG"
$PB -c "Set :Misc:Boot:Timeout 5" "$CONFIG"

# 设置SMBIOS机型
$PB -c "Set :PlatformInfo:Generic:SystemProductName iMac20,1" "$CONFIG"

# 启用所有Kernel > Add > kext
COUNT=$($PB -c "Print :Kernel:Add" "$CONFIG" | grep -c "Dict")
for ((i=0; i<$COUNT; i++)); do
    $PB -c "Set :Kernel:Add:$i:Enabled true" "$CONFIG"
done

# 添加-v参数(详细启动模式)
$PB -c "Delete :NVRAM:Add:7C436110-AB2A-4BBB-A880-FE41995C9F82:boot-args" "$CONFIG" 2>/dev/null
$PB -c "Add :NVRAM:Add:7C436110-AB2A-4BBB-A880-FE41995C9F82:boot-args string '-v keepsyms=1 debug=0x100'" "$CONFIG"

echo "OpenCore配置已更新"
plutil -lint "$CONFIG"

案例2:自动备份并修改系统LaunchAgent

#!/bin/bash
# 禁用特定的LaunchAgent(如不需要的Adobe后台服务)
PB="/usr/libexec/PlistBuddy"
AGENT_DIR="$HOME/Library/LaunchAgents"

for plist in "$AGENT_DIR"/com.adobe.*.plist; do
    [ -f "$plist" ] || continue
    # 备份
    cp "$plist" "$plist.bak"
    # 禁用(设置Disabled为true)
    $PB -c "Add :Disabled bool true" "$plist" 2>/dev/null ||     $PB -c "Set :Disabled true" "$plist"
    echo "已禁用: $(basename "$plist")"
done

案例3:从plist中提取系统信息用于监控

#!/bin/bash
# sysinfo.sh - 从SPHardwareDataType plist提取硬件信息
system_profiler SPHardwareDataType -xml > /tmp/hwinfo.plist

PB="/usr/libexec/PlistBuddy"
echo "=== 系统硬件信息 ==="
echo "型号: $($PB -c "Print :0:_items:0:machine_name" /tmp/hwinfo.plist)"
echo "CPU: $($PB -c "Print :0:_items:0:cpu_type" /tmp/hwinfo.plist)"
echo "内存: $($PB -c "Print :0:_items:0:physical_memory" /tmp/hwinfo.plist)"
echo "序列号: $($PB -c "Print :0:_items:0:serial_number" /tmp/hwinfo.plist)"
rm /tmp/hwinfo.plist

案例4:OpenCore kext注入顺序自动优化

OpenCore的config.plist中kext的加载顺序非常重要——Lilu必须在其他插件kext之前加载。以下脚本自动检查并修正加载顺序:

#!/bin/bash
# oc_kext_order.sh - 确保Lilu在第一位
CONFIG="EFI/OC/config.plist"
PB="/usr/libexec/PlistBuddy"

COUNT=$($PB -c "Print :Kernel:Add" "$CONFIG" | grep -c "Dict")

# 查找Lilu的位置
LILU_INDEX=-1
for ((i=0; i<$COUNT; i++)); do
    PATH=$($PB -c "Print :Kernel:Add:$i:BundlePath" "$CONFIG" 2>/dev/null)
    if [[ "$PATH" == *"Lilu.kext"* ]]; then
        LILU_INDEX=$i
        break
    fi
done

if [ $LILU_INDEX -gt 0 ]; then
    echo "Lilu不在位置0(当前: $LILU_INDEX),正在调整..."
    # 保存Lilu条目
    LILU_XML=$($PB -c "Print :Kernel:Add:$LILU_INDEX" "$CONFIG")
    # 删除原位置
    $PB -c "Delete :Kernel:Add:$LILU_INDEX" "$CONFIG"
    # 在开头插入(简化处理:使用Merge)
    echo "请手动将Lilu移动到Kernel>Add第0位"
elif [ $LILU_INDEX -eq 0 ]; then
    echo "Lilu已在正确位置(索引0)✅"
else
    echo "警告:未找到Lilu.kext!请检查EFI配置。"
fi

PlistBuddy的局限性与替代方案

PlistBuddy的不足

  • 无法直接处理嵌套搜索:如果你想找到"所有包含Enabled键的字典",PlistBuddy无法做到。它只支持显式路径。
  • 不支持正则表达式:无法按模式匹配键名。
  • 性能瓶颈:对大型plist(如包含数百个kext条目的config.plist),PlistBuddy的逐条操作效率较低。

替代方案:plutil + jq(JSON管道)

对于复杂操作,将plist转换为JSON后使用jq处理更为灵活:

# 转换plist为JSON,用jq查询
plutil -convert json -o - config.plist | jq '.PlatformInfo.Generic.SystemProductName'

# 批量替换SMBIOS字段
plutil -convert json -o - config.plist | jq '.PlatformInfo.Generic.SystemProductName = "iMac20,1"' | plutil -convert xml1 -o config_new.plist -

Python的plistlib

对于编程场景,Python内置的plistlib更灵活:

import plistlib

with open('config.plist', 'rb') as f:
    config = plistlib.load(f)

# 修改
config['PlatformInfo']['Generic']['SystemProductName'] = 'iMac20,1'

with open('config.plist', 'wb') as f:
    plistlib.dump(config, f)

总结

PlistBuddy是macOS系统管理员和黑苹果用户的秘密武器。它让你摆脱了对GUI编辑器的依赖,可以将plist操作无缝集成到自动化脚本中。从简单的键值修改到复杂的批量kext启用/禁用,从系统偏好调整到SMBIOS信息更换,PlistBuddy都可以胜任。

对于黑苹果用户,掌握PlistBuddy意味着:

  • 可以编写脚本自动验证和修复OpenCore配置
  • 批量管理LaunchAgent/LaunchDaemon(启动项优化)
  • 自动化系统偏好设置的导入导出
  • 将EFI配置备份与恢复流程标准化

结合plutil格式转换和jq/plistlib等工具,你甚至可以构建一套完整的黑苹果配置管理系统。希望这篇指南能帮助你打开plist自动化的大门!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。