launchd 是macOS(以前的Mac OS X)中的一个系统级进程管理框架,它负责启动、停止和管理系统和用户级别的进程、服务(守护进程)和脚本。可以将其视为类似Linux 系统下的systemd 或supervisor,它通过解析位于特定目录下的XML 格式的 .plist 配置文件来定义要执行的任务。
macOS launchd
通用教程
macOS
launchd
通用教程**,适合你以后自己写定时任务或服务。内容分为 基础概念 → 常见用法 → 常见问题 → 调试技巧,这样你可以按需选择写合适的 shell 脚本来跑。
1. 基础概念
launchd:macOS 的系统任务调度器,Apple 用它替代了
cron
。plist 文件:任务的配置文件,扩展名
.plist
,用 XML 格式写。位置:
~/Library/LaunchAgents/
→ 用户级任务(推荐放这里)/Library/LaunchAgents/
→ 所有用户可用/Library/LaunchDaemons/
→ 系统级任务,需要 root
2. plist 文件结构
一个最小可运行的 plist 文件长这样:
1 |
|
3. 定时方式
launchd 有几种常见的定时触发方式:
方式 1:间隔执行
1 | <key>StartInterval</key> |
→ 每 5 分钟执行一次。
方式 2:指定时间点执行
1 | <key>StartCalendarInterval</key> |
→ 每天 09:00 执行一次。
支持的键有:Minute
Hour
Day
Weekday
Month
。
方式 3:登录时执行
1 | <key>RunAtLoad</key> |
方式 4:文件变化触发
1 | <key>WatchPaths</key> |
→ 目录变化时执行。
4. 常用配置项
- 日志(推荐加上,方便调试)
1 | <key>StandardOutPath</key> |
- 环境变量(如果需要)
1 | <key>EnvironmentVariables</key> |
5. 操作命令
加载任务
1 | launchctl load ~/Library/LaunchAgents/com.example.task.plist |
卸载任务
1 | launchctl unload ~/Library/LaunchAgents/com.example.task.plist |
立即运行一次
1 | launchctl start com.example.task |
停止正在运行的任务
1 | launchctl stop com.example.task |
查看任务是否存在
1 | launchctl list | grep example |
6. 常见问题 & 解决方法
脚本没执行?
- 检查是否用绝对路径(脚本、python、venv)。
- 检查脚本是否
chmod +x
。
命令找不到?
- 加
EnvironmentVariables
或在脚本里写绝对路径。
- 加
运行了但没效果?
- 打开
/tmp/my_task.out
/tmp/my_task.err
看日志。
- 打开
plist 文件修改后没生效?
- 先
launchctl unload
再launchctl load
。
- 先
7. 调试技巧
在脚本开头打印环境:
1
2env >> /tmp/my_task.env.log
which python >> /tmp/my_task.env.log用
log show
查看系统日志:1
log show --predicate 'process == "sh"' --last 1h
简单测试:把任务改成
echo "Hello" >> /tmp/test.log
,确认launchd
能正常运行。
8. 踩坑记录
在 macOS 10.15 及以上版本(Catalina、Big Sur、Ventura 等),访问 Documents、Desktop、Downloads 或外部磁盘 的文件,需要 TCC(透明访问控制)授权。
1
2
3
4
比如你的脚本在 ~/Documents/software/XXX/ 目录下
launchd 以 GUI 用户身份运行,但 没有权限访问 Documents
手动在终端运行可以成功,因为终端已经在你的用户会话下,有访问权限
launchd 运行时 环境不同,TCC 会拦截,导致 Operation not permitted
解决方案:改脚本目录(最简单),远离Documents、Desktop、Downloads 或外部磁盘
1 | 比如你的脚本在 ~/Documents/software/XXX/ 目录下 |
✅ 总结:
- cron → 用 launchd(Apple 推荐)
- 绝对路径 > 环境变量(最稳妥)
- 调试靠日志(
StandardOutPath
/StandardErrorPath
)