macOS自启动服务由launchd管理,需编写符合规范的.plist文件并正确放置到~/Library/LaunchAgents/(用户级)或/Library/LaunchDaemons/(系统级),注意Label唯一性、绝对路径、EnvironmentVariables设置及launchctl命令加载调试。

macOS 的自启动服务通过 launchd 管理,核心是编写正确的 .plist 配置文件,并将其正确加载到系统或用户域中。关键在于路径、权限、标签(Label)唯一性以及触发条件的准确设置。
plist 文件必须满足的基本规范
Launchd 的配置文件是 XML 格式(`.plist`),需严格遵循 Apple 定义的结构。常见错误包括标签名拼写错误(如 RunAtLoad 写成 RunAtLoad)、缺少必要键(如 Label)、值类型不匹配(布尔值必须用 <true/> 或 <false/>,不能写 yes 或 1)。
-
Label必须全局唯一,推荐使用反向域名格式,例如com.example.myserver -
ProgramArguments是数组,首项为可执行文件路径,后续为参数;不要用Program单独指定命令(已废弃) - 路径中的波浪号
~不会被自动展开,需写绝对路径,如/Users/username/bin/myscript.sh - 若脚本需环境变量(如
$PATH),应在 plist 中显式设置EnvironmentVariables字典
加载位置决定作用域和权限
plist 文件放在不同目录,由不同主体加载,权限和生命周期也不同:
-
用户级服务(推荐日常使用):放至
~/Library/LaunchAgents/,随用户登录启动,以当前用户身份运行,无需 sudo -
系统级服务(需管理员权限):放至
/Library/LaunchDaemons/,系统启动时加载,以root身份运行;文件属主应为root:wheel,权限设为644 -
/System/Library/LaunchDaemons/和/System/Library/LaunchAgents/为系统保留,普通用户不可写,也不应修改
常用启动与调试操作
加载、卸载和排错都通过 launchctl 命令完成,注意命令语法在 macOS 12+ 已统一为子命令形式:
- 加载服务:
launchctl load ~/Library/LaunchAgents/com.example.myservice.plist - 立即启动(即使未设
RunAtLoad):launchctl start com.example.myservice - 停止并卸载:
launchctl stop com.example.myservice && launchctl unload ~/Library/LaunchAgents/com.example.myservice.plist - 查看状态:
launchctl list | grep example或launchctl print gui/$(id -u)/com.example.myservice - 日志排查:服务输出默认重定向到
system.log或console,可在“控制台”App 中筛选进程名;也可在 plist 中添加StandardOutPath和StandardErrorPath指定日志文件
典型配置示例(用户级后台脚本)
以下是一个监听文件变化并执行脚本的用户级 agent 示例:
<?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>Label</key>
<string>com.example.watch-folder</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>/Users/username/scripts/watch.py</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>EnvironmentVariables</key>
<dict>
<key>PATH</key>
<string>/usr/local/bin:/opt/homebrew/bin:/usr/bin:/bin</string>
</dict>
<key>StandardOutPath</key>
<string>/Users/username/logs/watch.log</string>
<key>StandardErrorPath</key>
<string>/Users/username/logs/watch.err</string>
</dict>
</plist>
保存为 ~/Library/LaunchAgents/com.example.watch-folder.plist,确保脚本有执行权限(chmod +x /Users/username/scripts/watch.py),再执行 launchctl load 即可生效。










